aboutsummaryrefslogtreecommitdiffstats
path: root/cmd.c
diff options
context:
space:
mode:
Diffstat (limited to 'cmd.c')
-rw-r--r--cmd.c2464
1 files changed, 2464 insertions, 0 deletions
diff --git a/cmd.c b/cmd.c
new file mode 100644
index 0000000..45ca1c0
--- /dev/null
+++ b/cmd.c
@@ -0,0 +1,2464 @@
+/*
+ * cmd.c -- functions for powwow's built-in #commands
+ *
+ * (created: Finn Arne Gangstad (Ilie), Dec 25th, 1993)
+ *
+ * Copyright (C) 1998 by Massimiliano Ghilardi
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <ctype.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <dlfcn.h>
+
+#include "defines.h"
+#include "main.h"
+#include "utils.h"
+#include "beam.h"
+#include "cmd.h"
+#include "cmd2.h"
+#include "edit.h"
+#include "list.h"
+#include "map.h"
+#include "tcp.h"
+#include "tty.h"
+#include "eval.h"
+#include "log.h"
+
+/* local function declarations */
+#define _ __P ((char *arg))
+
+static void cmd_help _, cmd_shell _,
+ cmd_action _, cmd_add _, cmd_alias _, cmd_at _, cmd_beep _, cmd_bind _,
+ cmd_cancel _, cmd_capture _, cmd_clear _, cmd_connect _, cmd_cpu _,
+ cmd_do _, cmd_delim _, cmd_edit _, cmd_emulate _, cmd_exe _,
+ cmd_file _, cmd_for _, cmd_hilite _, cmd_history _, cmd_host _,
+ cmd_identify _, cmd_if _, cmd_in _, cmd_init _, cmd_isprompt _,
+ cmd_key _, cmd_keyedit _,
+ cmd_load _, cmd_map _, cmd_mark _, cmd_movie _,
+ cmd_net _, cmd_nice _, cmd_option _,
+ cmd_prefix _, cmd_print _, cmd_prompt _, cmd_put _,
+ cmd_qui _, cmd_quit _, cmd_quote _,
+ cmd_rawsend _, cmd_rawprint _, cmd_rebind _, cmd_rebindall _, cmd_rebindALL _,
+ cmd_record _, cmd_request _, cmd_reset _, cmd_retrace _,
+ cmd_save _, cmd_send _, cmd_setvar _, cmd_snoop _, cmd_spawn _, cmd_stop _,
+ cmd_time _, cmd_var _, cmd_ver _, cmd_while _, cmd_write _,
+ cmd_eval _, cmd_zap _, cmd_module _, cmd_group _;
+
+#ifdef BUG_TELNET
+static void cmd_color _;
+#endif
+
+#undef _
+
+/* This must be init'd now at runtime */
+cmdstruct *commands = NULL;
+
+/* The builtin commands */
+cmdstruct default_commands[] =
+{
+ {NULL,"help", "[keys|math|command]\tthis text, or help on specified topic", cmd_help,NULL},
+ {NULL,"17", "command\t\t\trepeat `command' 17 times", (function_str)0,NULL},
+#ifndef NO_SHELL
+ {NULL,"!", "shell-command\t\texecute a shell command using /bin/sh", cmd_shell,NULL},
+#endif
+ {NULL,"action", "[[<|=|>|%][+|-]name] [{pattern|(expression)} [=[command]]]\n\t\t\t\tdelete/list/define actions", cmd_action,NULL},
+ {NULL,"add", "{string|(expr)}\t\tadd the string to word completion list", cmd_add,NULL},
+ {NULL,"alias", "[name[=[text]]]\t\tdelete/list/define aliases", cmd_alias,NULL},
+ {NULL,"at", "[name [(time-string) [command]]\tset time of delayed label", cmd_at,NULL},
+ {NULL,"beep", "\t\t\t\tmake your terminal beep (like #print (*7))", cmd_beep,NULL},
+ {NULL,"bind", "[edit|name [seq][=[command]]]\tdelete/list/define key bindings", cmd_bind,NULL},
+ {NULL,"cancel", "[number]\t\tcancel editing session", cmd_cancel,NULL},
+ {NULL,"capture", "[filename]\t\tbegin/end of capture to file", cmd_capture,NULL},
+ {NULL,"clear", "\t\t\tclear input line (use from spawned programs)", cmd_clear,NULL},
+#ifdef BUG_TELNET
+ {NULL,"color", "attr\t\t\tset default colors/attributes", cmd_color,NULL},
+#endif
+ {NULL,"connect", "[connect-id [initstr] [address port]\topen a new connection", cmd_connect,NULL},
+ {NULL,"cpu", "\t\t\t\tshow CPU time used by powwow", cmd_cpu,NULL},
+ {NULL,"delim", "[normal|program|{custom [chars]}]\n\t\t\t\tset word completion delimeters", cmd_delim,NULL},
+ {NULL,"do", "(expr) command\t\trepeat `command' (expr) times", cmd_do,NULL},
+ {NULL,"edit", "\t\t\t\tlist editing sessions", cmd_edit,NULL},
+ {NULL,"emulate", "[<|!]{text|(expr)}\tprocess result as if received from host", cmd_emulate,NULL},
+ {NULL,"exe", "[<|!]{text|(string-expr)}\texecute result as if typed from keyboard", cmd_exe,NULL},
+ {NULL,"file", "[=[filename]]\t\tset/show powwow definition file", cmd_file,NULL},
+ {NULL,"for", "([init];check;[loop]) command\twhile `check' is true exec `command'", cmd_for,NULL},
+ {NULL,"group", "[name] [on|off|list]\tgroup alias/action manipulation'", cmd_group,NULL},
+ {NULL,"hilite", "[attr]\t\t\thighlight your input line", cmd_hilite,NULL},
+ {NULL,"history", "[{number|(expr)}]\tlist/execute commands in history", cmd_history,NULL},
+ {NULL,"host", "[hostname port]]\tset/show address of default host", cmd_host,NULL},
+ {NULL,"identify", "[startact [endact]]\tsend MUME client identification", cmd_identify,NULL},
+ {NULL,"if", "(expr) instr1 [; #else instr2]\tif `expr' is true execute `instr1'\n\t\t\t\totherwise execute `instr2'", cmd_if,NULL},
+ {NULL,"in", "[label [(delay) [command]]]\tdelete/list/define delayed labels", cmd_in,NULL},
+ {NULL,"init", "[=[command]]\t\tdefine command to execute on connect to host", cmd_init,NULL},
+ {NULL,"isprompt", "\t\t\trecognize a prompt as such", cmd_isprompt,NULL},
+ {NULL,"key", "name\t\t\texecute the `name' key binding", cmd_key,NULL},
+ {NULL,"keyedit", "editing-name\t\trun a line-editing function", cmd_keyedit,NULL},
+ {NULL,"load", "[filename]\t\tload powwow settings from file", cmd_load,NULL},
+ {NULL,"module","[filename]\t\tload shared library extension", cmd_module,NULL},
+ {NULL,"map", "[-[number]|walksequence]\tshow/clear/edit (auto)map", cmd_map,NULL},
+ {NULL,"mark", "[string[=[attr]]]\t\tdelete/list/define markers", cmd_mark,NULL},
+ {NULL,"movie", "[filename]\t\tbegin/end of movie record to file", cmd_movie,NULL},
+ {NULL,"net", "\t\t\t\tprint amount of data received from/sent to host", cmd_net,NULL},
+ {NULL,"nice", "[{number|(expr)}[command]]\tset/show priority of new actions/marks", cmd_nice,NULL},
+ {NULL,"option", "[[+|-|=]name]\t\tturn various options", cmd_option,NULL},
+ {NULL,"prefix", "string\t\t\tprefix all lines with string", cmd_prefix,NULL},
+ {NULL,"", "(expr)\t\t\tevaluate expression, trashing result", cmd_eval,NULL},
+ {NULL,"print", "[<|!][text|(expr)]\tprint text/result on screen, appending a \\n\n\t\t\t\tif no argument, prints value of variable $0", cmd_print,NULL},
+ {NULL,"prompt", "[[<|=|>|%][+|-]name] [{pattern|(expression)} [=[prompt-command]]]\n\t\t\t\tdelete/list/define actions on prompts", cmd_prompt,NULL},
+ {NULL,"put", "{text|(expr)}\t\tput text/result of expression in history", cmd_put,NULL},
+ {NULL,"qui", "\t\t\t\tdo nothing", cmd_qui,NULL},
+ {NULL,"quit", "\t\t\t\tquit powwow", cmd_quit,NULL},
+ {NULL,"quote", "[on|off]\t\t\ttoggle verbatim-flag on/off", cmd_quote,NULL},
+ {NULL,"rawsend", "{string|(expr)}\t\tsend raw data to the MUD", cmd_rawsend,NULL},
+ {NULL,"rawprint", "{string|(expr)}\t\tsend raw data to the screen", cmd_rawprint,NULL},
+ {NULL,"rebind", "name [seq]\t\tchange sequence of a key binding", cmd_rebind,NULL},
+ {NULL,"rebindall", "\t\t\trebind all key bindings", cmd_rebindall,NULL},
+ {NULL,"rebindALL", "\t\t\trebind ALL key bindings, even trivial ones", cmd_rebindALL,NULL},
+ {NULL,"record", "[filename]\t\tbegin/end of record to file", cmd_record,NULL},
+ {NULL,"request", "[editor][prompt][all]\tsend various identification strings", cmd_request,NULL},
+ {NULL,"reset", "<list-name>\t\tclear the whole defined list and reload default", cmd_reset,NULL},
+ {NULL,"retrace", "[number]\t\tretrace the last number steps", cmd_retrace,NULL},
+ {NULL,"save", "[filename]\t\tsave powwow settings to file", cmd_save,NULL},
+ {NULL,"send", "[<|!]{text|(expr)}\teval expression, sending result to the MUD", cmd_send,NULL},
+ {NULL,"setvar", "name[=text|(expr)]\tset/show internal limits and variables", cmd_setvar,NULL},
+ {NULL,"snoop", "connect-id\t\ttoggle output display for connections", cmd_snoop,NULL},
+ {NULL,"spawn", "connect-id command\ttalk with a shell command", cmd_spawn,NULL},
+ {NULL,"stop", "\t\t\t\tremove all delayed commands from active list", cmd_stop,NULL},
+ {NULL,"time", "\t\t\t\tprint current time and date", cmd_time,NULL},
+ {NULL,"var", "variable [= [<|!]{string|(expr)} ]\twrite result into the variable", cmd_var,NULL},
+ {NULL,"ver", "\t\t\t\tshow powwow version", cmd_ver,NULL},
+ {NULL,"while", "(expr) instr\t\twhile `expr' is true execute `instr'", cmd_while,NULL},
+ {NULL,"write", "[>|!](expr;name)\t\twrite result of expr to `name' file", cmd_write,NULL},
+ {NULL,"zap", "connect-id\t\t\tclose a connection", cmd_zap,NULL},
+ {NULL,(char *)0, (char *)0, (function_str)0,NULL}
+};
+
+char *_cmd_sort_name( cmdstruct *cmd ) {
+ if( cmd -> sortname == NULL )
+ return( cmd -> name );
+ else
+ return( cmd -> sortname );
+}
+
+/* Adds a cmd to commands (inserts the ptr in the list, DO NOT FREE IT) */
+void cmd_add_command( cmdstruct *cmd ) {
+ /* do insert/sort */
+ cmdstruct *c = commands;
+
+ /*
+ * make sure it doesn't override another commmand
+ * this is important not just because it'd be irritating,
+ * but if a module defined the command in the global static
+ * space, it would create an infinite loop because the -> next
+ * ptr would point at itself
+ *
+ * doing it up front because based on the sortname, we may never see
+ * the dup item if we do it at sort time
+ */
+ for( c = commands; c != NULL; c = c -> next ) {
+ if( strcmp( cmd -> name, c -> name ) == 0 ) {
+ PRINTF( "#error %s is already defined\n", c -> name );
+ return;
+ }
+ }
+
+
+ /* catch insertion to head of list */
+ if( commands == NULL ) {
+ /* no commands yet */
+ commands = cmd;
+ cmd -> next = NULL;
+ return;
+ }
+
+ if( strcmp( _cmd_sort_name( commands ), _cmd_sort_name( cmd ) ) > 0 ) {
+ /* this is lower in sort than every item, so
+ * make it the head of the list */
+ cmd -> next = commands;
+ commands = cmd;
+ return;
+ }
+
+ for( c = commands; c != NULL; c = c -> next ) {
+ if( strcmp( _cmd_sort_name( cmd ), _cmd_sort_name( c ) ) >= 0 ) {
+ /* Need second check to handle empty string case */
+ if( c -> next == NULL || strcmp( _cmd_sort_name( cmd ), _cmd_sort_name( c -> next ) ) <= 0 ) {
+ /*PRINTF( "Inserting %s after %s\n", cmd -> name, c -> name ); */
+
+ /* insert after this one, it is greater than this
+ * entry but less than the next */
+ cmd -> next = c -> next;
+ c -> next = cmd;
+ return;
+ }
+ }
+ }
+
+ PRINTF( "ERROR INSERTING COMMAND\n" );
+}
+
+/* Init the command listing, called from main */
+void _cmd_init() {
+ int i;
+
+ /* Now add the default command list */
+ for( i = 0; default_commands[ i ].name; i++ )
+ cmd_add_command( &default_commands[ i ] );
+}
+
+static void cmd_module __P1 (char *,arg) {
+ char libname[1024];
+ void *lib;
+ void (*func)();
+
+ arg = skipspace(arg);
+
+ bzero( libname, 1024 );
+ if( *arg == '.' || *arg == '/' ) {
+ /* No path mungling */
+ strncpy( libname, arg, 1024 );
+ }else{
+ snprintf( libname, 1024, "/usr/local/lib/powwow/%s", arg );
+ }
+
+ /* open lib */
+ lib = dlopen( libname, RTLD_LAZY );
+ if( ! lib ) {
+ PRINTF( "#lib error: %s\n", dlerror() );
+ return;
+ }
+
+ func = dlsym( lib, "powwow_init" );
+ if( func ) {
+ (*func)();
+ }else{
+ PRINTF( "#lib error: %s\n", dlerror() );
+ }
+}
+
+static void cmd_group __P1 (char *,arg) {
+ char *group;
+ int active;
+ aliasnode *p;
+ actionnode *a;
+
+ arg = skipspace(arg);
+
+ if( *arg ) {
+ arg = first_regular( group = arg, ' ');
+ *arg = '\0';
+ arg = skipspace( arg + 1 );
+
+ if( strcmp( arg, "on" ) == 0 ) {
+ active = 1;
+ }else if( strcmp( arg, "off" ) == 0 ) {
+ active = 0;
+ }else if( strcmp( arg, "list" ) == 0 ) {
+ PRINTF( "#not implemented\n" );
+ return;
+ }else{
+ PRINTF( "#unknown group command, use off/on/list\n" );
+ return;
+ }
+
+ /* Now loop over all aliases/actions by groupname and toggle */
+ for( p = sortedaliases; p; p = p -> snext ) {
+ if( p -> group && strcmp( p -> group, group ) == 0 ) {
+ p -> active = active;
+ }
+ }
+
+ /* Same for actions */
+ for( a = actions; a; a = a -> next ) {
+ if( a -> group && strcmp( a -> group, group ) == 0 ) {
+ a -> active = active;
+ }
+ }
+ }else{
+ PRINTF( "#group name required\n" );
+ }
+}
+
+static void cmd_help __P1 (char *,arg)
+{
+ int i, size;
+ char *text, *tmp;
+ FILE *f;
+ char line[BUFSIZE];
+ int len;
+ cmdstruct *c;
+
+ arg = skipspace(arg);
+ if (*arg == '#') arg++;
+ if (!*arg) {
+ size = 25;
+ for( c = commands; c != NULL; c = c -> next )
+ size += strlen(c -> name) + strlen(c -> help) + 5;
+
+ text = tmp = (char *)malloc(size);
+ if (!text) {
+ errmsg("malloc");
+ return;
+ }
+
+ /* do not use sprintf() return value, almost every OS returns a different thing. */
+ sprintf(tmp, "#help\n#commands available:\n");
+ tmp += strlen(tmp);
+
+ for( c = commands; c != NULL; c = c -> next ) {
+ sprintf(tmp, "#%s %s\n", c -> name, c -> help);
+ tmp += strlen(tmp);
+ }
+
+ message_edit(text, strlen(text), 1, 1);
+ return;
+ }
+
+ if (!strncmp(arg, "copyright", strlen(arg))) {
+ int fd, left, got = 0;
+ struct stat stbuf;
+
+ if (stat(copyfile, &stbuf) < 0) {
+ errmsg("stat(copyright file)");
+ return;
+ }
+
+ if (!(text = (char *)malloc(left = stbuf.st_size))) {
+ errmsg("malloc");
+ return;
+ }
+ if ((fd = open(copyfile, O_RDONLY)) < 0) {
+ errmsg("open(copyright file)");
+ free(text);
+ return;
+ }
+ while (left > 0) {
+ while ((i = read(fd, text + got, left)) < 0 && errno == EINTR)
+ ;
+ if (i < 0 && errno == EINTR) {
+ errmsg("read (copyright file)");
+ free(text);
+ close(fd);
+ return;
+ }
+ if (i == 0)
+ break;
+ left -= i, got += i;
+ }
+ close(fd);
+ message_edit(text, strlen(text), 1, 1);
+ return;
+ }
+
+ /* !copyright */
+
+ f = fopen(helpfile, "r");
+ if (!f) {
+ PRINTF("#cannot open help file `%s': %s\n",
+ helpfile, strerror(errno));
+ return;
+ }
+
+ while ((tmp = fgets(line, BUFSIZE, f)) &&
+ (line[0] != '@' || strncmp(line + 1, arg, strlen(arg))))
+ ;
+
+ if (!tmp) {
+ PRINTF("#no entry for `%s' in the help file.\n", arg);
+ fclose(f);
+ return;
+ }
+
+ if (!(text = (char *)malloc(size = BUFSIZE))) {
+ errmsg("malloc");
+ fclose(f);
+ return;
+ }
+
+ memcpy(text, line, i = strlen(line));
+
+ while (fgets(line, BUFSIZE, f) && line[0] == '@')
+ ; /* allow multiple commands to share the same help */
+
+ do {
+ if ((len = strlen(line)) >= size - i) {
+ /* Not enough space in current buffer */
+
+ if (!(tmp = (char *)malloc(size += BUFSIZE))) {
+ errmsg("malloc");
+ free(text);
+ fclose(f);
+ return;
+ } else {
+ memcpy(tmp, text, i);
+ free(text);
+ text = tmp;
+ }
+ }
+ memcpy(text + i, line, len);
+ i += len;
+ } while (fgets(line, BUFSIZE, f) && line[0] != '@');
+
+ fclose(f);
+ text[i] = '\0'; /* safe, there is space */
+ message_edit(text, strlen(text), 1, 1);
+}
+
+static void cmd_clear __P1 (char *,arg)
+{
+ if (line_status == 0) {
+ clear_input_line(opt_compact);
+ if (!opt_compact) {
+ tty_putc('\n');
+ col0 = 0;
+ }
+ status(1);
+ }
+}
+
+#ifndef NO_SHELL
+static void cmd_shell __P1 (char *,arg)
+{
+ if (!*arg) {
+ if (echo_int) {
+ PRINTF("#that's easy.\n");
+ }
+ } else {
+ tty_quit();
+
+ system(arg);
+
+ tty_start();
+ tty_gotoxy(col0 = 0, line0 = lines -1);
+ tty_puts(tty_clreoln);
+ }
+}
+#endif
+
+static void cmd_alias __P1 (char *,arg)
+{
+ arg = skipspace(arg);
+ if (!*arg)
+ show_aliases();
+ else
+ parse_alias(arg);
+}
+
+static void cmd_action __P1 (char *,arg)
+{
+ arg = skipspace(arg);
+ if (!*arg)
+ show_actions();
+ else
+ parse_action(arg, 0);
+}
+
+static void cmd_prompt __P1 (char *,arg)
+{
+ arg = skipspace(arg);
+ if (!*arg)
+ show_prompts();
+ else
+ parse_action(arg, 1);
+}
+
+static void cmd_beep __P1 (char *,arg)
+{
+ tty_putc('\007');
+}
+
+/*
+ * create/list/edit/delete bindings
+ */
+static void cmd_bind __P1 (char *,arg)
+{
+ arg = skipspace(arg);
+ if (!*arg)
+ show_binds(0);
+ else if (!strcmp(arg, "edit"))
+ show_binds(1);
+ else
+ parse_bind(arg);
+}
+
+static void cmd_delim __P1 (char *,arg)
+{
+ char buf[BUFSIZE];
+ int n;
+
+ arg = skipspace(arg);
+ if (!*arg) {
+ PRINTF("#delim: `%s' (%s)\n", delim_name[delim_mode], DELIM);
+ return;
+ }
+
+ arg = split_first_word(buf, BUFSIZE, arg);
+ n = 0;
+ while (n < DELIM_MODES && strncmp(delim_name[n], buf, strlen(buf)) != 0)
+ n++;
+
+ if (n >= DELIM_MODES) {
+ PRINTF("#delim [normal|program|{custom <chars>}\n");
+ return;
+ }
+
+ if (n == DELIM_CUSTOM) {
+ if (!strchr(arg, ' ')) {
+ my_strncpy(buf+1, arg, BUFSIZE-2);
+ *buf = ' '; /* force ' ' in the delims */
+ arg = buf;
+ }
+ unescape(arg);
+ set_custom_delimeters(arg);
+ } else
+ delim_mode = n;
+}
+
+static void cmd_do __P1 (char *,arg)
+{
+ int type;
+ long result;
+
+ arg = skipspace(arg);
+ if (*arg != '(') {
+ PRINTF("#do: ");
+ print_error(error=MISMATCH_PAREN_ERROR);
+ return;
+ }
+ arg++;
+
+ type = evall(&result, &arg);
+ if (REAL_ERROR) return;
+
+ if (type != TYPE_NUM) {
+ PRINTF("#do: ");
+ print_error(error=NO_NUM_VALUE_ERROR);
+ return;
+ }
+
+ if (*arg == ')') { /* skip the ')' */
+ if (*++arg == ' ')
+ arg++;
+ }
+ else {
+ PRINTF("#do: ");
+ print_error(error=MISSING_PAREN_ERROR);
+ return;
+ }
+
+ if (result >= 0)
+ while (!error && result--)
+ (void)parse_instruction(arg, 1, 0, 1);
+ else {
+ PRINTF("#do: bogus repeat count `%ld'\n", result);
+ }
+}
+
+static void cmd_hilite __P1 (char *,arg)
+{
+ int attr;
+
+ arg = skipspace(arg);
+ attr = parse_attributes(arg);
+ if (attr == -1) {
+ PRINTF("#attribute syntax error.\n");
+ if (echo_int)
+ show_attr_syntax();
+ } else {
+ attr_string(attr, edattrbeg, edattrend);
+
+ edattrbg = ATTR(attr) & ATTR_INVERSE ? 1
+ : BACKGROUND(attr) != NO_COLOR || ATTR(attr) & ATTR_BLINK;
+
+ if (echo_int) {
+ PRINTF("#input highlighting is now %so%s%s.\n",
+ edattrbeg, (attr == NOATTRCODE) ? "ff" : "n",
+ edattrend);
+ }
+ }
+}
+
+static void cmd_history __P1 (char *,arg)
+{
+ int num = 0;
+ long buf;
+
+ arg = skipspace(arg);
+
+ if (history_done >= MAX_HIST) {
+ print_error(error=HISTORY_RECURSION_ERROR);
+ return;
+ }
+ history_done++;
+
+ if (*arg == '(') {
+ arg++;
+ num = evall(&buf, &arg);
+ if (!REAL_ERROR && num != TYPE_NUM)
+ error=NO_NUM_VALUE_ERROR;
+ if (REAL_ERROR) {
+ PRINTF("#history: ");
+ print_error(error=NO_NUM_VALUE_ERROR);
+ return;
+ }
+ num = (int)buf;
+ } else
+ num = atoi(arg);
+
+ if (num > 0)
+ exe_history(num);
+ else
+ show_history(-num);
+}
+
+static void cmd_host __P1 (char *,arg)
+{
+ char newhost[BUFSIZE];
+
+ arg = skipspace(arg);
+ if (*arg) {
+ arg = split_first_word(newhost, BUFSIZE, arg);
+ if (*arg) {
+ my_strncpy(hostname, newhost, BUFSIZE-1);
+ portnumber = atoi(arg);
+ if (echo_int) {
+ PRINTF("#host set to: %s %d\n", hostname, portnumber);
+ }
+ } else {
+ PRINTF("#host: missing portnumber.\n");
+ }
+ } else if (*hostname)
+ sprintf(inserted_next, "#host %.*s %d", BUFSIZE-INTLEN-8,
+ hostname, portnumber);
+ else {
+ PRINTF("#syntax: #host hostname port\n");
+ }
+}
+
+static void cmd_request __P1 (char *,arg)
+{
+ char *idprompt = "~$#EP2\nG\n";
+ char *ideditor = "~$#EI\n";
+ char buf[256];
+ int all, len;
+
+ if (tcp_fd == -1) {
+ PRINTF("#not connected to a MUD!\n");
+ return;
+ }
+ while (*(arg = skipspace(arg))) {
+ arg = split_first_word(buf, 256, arg);
+ if (*buf) {
+ all = !strcmp(buf, "all");
+ len = strlen(buf);
+ if ((all || !strncmp(buf, "editor", len))) {
+ tcp_raw_write(tcp_fd, ideditor, strlen(ideditor));
+ CONN_LIST(tcp_fd).flags |= IDEDITOR;
+ if (echo_int) {
+ PRINTF("#request editor: %s done!\n", ideditor);
+ }
+ }
+ if ((all || !strncmp(buf, "prompt", len))) {
+ tcp_raw_write(tcp_fd, idprompt, strlen(idprompt));
+ CONN_LIST(tcp_fd).flags |= IDPROMPT;
+ if (echo_int) {
+ PRINTF("#request prompt: %s done!\n", idprompt);
+ }
+ }
+ }
+ }
+
+}
+
+static void cmd_identify __P1 (char *,arg)
+{
+ edit_start[0] = edit_end[0] = '\0';
+ if (*arg) {
+ char *p = strchr(arg, ' ');
+ if (p) {
+ *(p++) = '\0';
+ my_strncpy(edit_end, p, BUFSIZE-1);
+ }
+ my_strncpy(edit_start, arg, BUFSIZE-1);
+ }
+ cmd_request("editor");
+}
+
+static void cmd_in __P1 (char *,arg)
+{
+ char *name;
+ long millisec, buf;
+ int type;
+ delaynode **p;
+
+ arg = skipspace(arg);
+ if (!*arg) {
+ show_delays();
+ return;
+ }
+
+ arg = first_regular(name = arg, ' ');
+ if (*arg)
+ *arg++ = 0;
+
+ unescape(name);
+
+ p = lookup_delay(name, 0);
+ if (!*p) p = lookup_delay(name, 1);
+
+ if (!*arg && !*p) {
+ PRINTF("#unknown delay label, cannot show: `%s'\n", name);
+ return;
+ }
+ if (!*arg) {
+ show_delaynode(*p, 1);
+ return;
+ }
+ if (*arg != '(') {
+ PRINTF("#in: ");
+ print_error(error=MISMATCH_PAREN_ERROR);
+ return;
+ }
+ arg++; /* skip the '(' */
+
+ type = evall(&buf, &arg);
+ if (!REAL_ERROR) {
+ if (type!=TYPE_NUM)
+ error=NO_NUM_VALUE_ERROR;
+ else if (*arg != ')')
+ error=MISSING_PAREN_ERROR;
+ }
+ if (REAL_ERROR) {
+ PRINTF("#in: ");
+ print_error(error);
+ return;
+ }
+
+ arg = skipspace(arg+1);
+ millisec = buf;
+ if (*p && millisec)
+ change_delaynode(p, arg, millisec);
+ else if (!*p && millisec) {
+ if (*arg)
+ new_delaynode(name, arg, millisec);
+ else {
+ PRINTF("#cannot create delay label without a command.\n");
+ }
+ } else if (*p && !millisec) {
+ if (echo_int) {
+ PRINTF("#deleting delay label: %s %s\n", name, (*p)->command);
+ }
+ delete_delaynode(p);
+ } else {
+ PRINTF("#unknown delay label, cannot delete: `%s'\n", name);
+ }
+}
+
+static void cmd_at __P1 (char *,arg)
+{
+ char *name, *buf = NULL;
+ char dayflag=0;
+ struct tm *twhen;
+ int num, hour = -1, minute = -1, second = -1;
+ delaynode **p;
+ long millisec;
+ ptr pbuf = (ptr)0;
+
+ arg = skipspace(arg);
+ if (!*arg) {
+ show_delays();
+ return;
+ }
+
+ arg = first_regular(name = arg, ' ');
+ if (*arg)
+ *arg++ = 0;
+
+ unescape(name);
+
+ p = lookup_delay(name, 0);
+ if (!*p) p = lookup_delay(name, 1);
+
+ if (!*arg && !*p) {
+ PRINTF("#unknown delay label, cannot show: `%s'\n", name);
+ return;
+ }
+ if (!*arg) {
+ show_delaynode(*p, 2);
+ return;
+ }
+ if (*arg != '(') {
+ PRINTF("#in: ");
+ print_error(error=MISMATCH_PAREN_ERROR);
+ return;
+ }
+ arg++; /* skip the '(' */
+
+ (void)evalp(&pbuf, &arg);
+ if (REAL_ERROR) {
+ print_error(error);
+ ptrdel(pbuf);
+ return;
+ }
+ if (pbuf) {
+ /* convert time-string into hour, minute, second */
+ buf = skipspace(ptrdata(pbuf));
+ if (!*buf || !isdigit(*buf)) {
+ PRINTF("#at: ");
+ print_error(error=NO_NUM_VALUE_ERROR);
+ ptrdel(pbuf);
+ return;
+ }
+ num = atoi(buf);
+ second = num % 100;
+ minute = (num /= 100) % 100;
+ hour = num / 100;
+ }
+ if (hour < 0 || hour>23 || minute < 0 || minute>59
+ || second < 0 || second>59) {
+
+ PRINTF("#at: #error: invalid time `%s'\n",
+ pbuf && buf ? buf : (char *)"");
+ error=OUT_RANGE_ERROR;
+ ptrdel(pbuf);
+ return;
+ }
+ ptrdel(pbuf);
+
+ if (*arg == ')') { /* skip the ')' */
+ if (*++arg == ' ')
+ arg++;
+ }
+ else {
+ PRINTF("#at: ");
+ print_error(error=MISSING_PAREN_ERROR);
+ return;
+ }
+
+ arg = skipspace(arg);
+ update_now();
+ twhen = localtime((time_t *)&now.tv_sec);
+ /* put current year, month, day in calendar struct */
+
+ if (hour < twhen->tm_hour ||
+ (hour == twhen->tm_hour &&
+ (minute < twhen->tm_min ||
+ (minute == twhen->tm_min &&
+ second <= twhen->tm_sec)))) {
+ dayflag = 1;
+ /* it is NOT possible to define an #at refering to the past */
+ }
+
+ /* if you use a time smaller than the current, it refers to tomorrow */
+
+ millisec = (hour - twhen->tm_hour) * 3600 + (minute - twhen->tm_min) * 60 +
+ second - twhen->tm_sec + (dayflag ? 24*60*60 : 0);
+ millisec *= mSEC_PER_SEC; /* Comparing time with current calendar,
+ we finally got the delay */
+ millisec -= now.tv_usec / uSEC_PER_mSEC;
+
+ if (*p)
+ change_delaynode(p, arg, millisec);
+ else
+ if (*arg)
+ new_delaynode(name, arg, millisec);
+ else {
+ PRINTF("#cannot create delay label without a command.\n");
+ }
+}
+
+static void cmd_init __P1 (char *,arg)
+{
+ arg = skipspace(arg);
+
+ if (*arg == '=') {
+ if (*++arg) {
+ my_strncpy(initstr, arg, BUFSIZE-1);
+ if (echo_int) {
+ PRINTF("#init: %s\n", initstr);
+ }
+ } else {
+ *initstr = '\0';
+ if (echo_int) {
+ PRINTF("#init cleared.\n");
+ }
+ }
+ } else
+ sprintf(inserted_next, "#init =%.*s", BUFSIZE-8, initstr);
+}
+
+static void cmd_isprompt __P1 (char *,arg)
+{
+ if (tcp_fd == tcp_main_fd) {
+ int i;
+ long l;
+ arg = skipspace(arg);
+ if (*arg == '(') {
+ arg++;
+ i = evall(&l, &arg);
+ if (!REAL_ERROR) {
+ if (i!=TYPE_NUM)
+ error=NO_NUM_VALUE_ERROR;
+ else if (*arg != ')')
+ error=MISSING_PAREN_ERROR;
+ }
+ if (REAL_ERROR) {
+ PRINTF("#isprompt: ");
+ print_error(error);
+ return;
+ }
+ i = (int)l;
+ } else
+ i = atoi(arg);
+
+ if (i == 0)
+ surely_isprompt = -1;
+ else if (i < 0) {
+ if (i > -NUMPARAM && *VAR[-i].str)
+ ptrtrunc(prompt->str, surely_isprompt = ptrlen(*VAR[-i].str));
+ } else
+ ptrtrunc(prompt->str, surely_isprompt = i);
+ }
+}
+
+static void cmd_key __P1 (char *,arg)
+{
+ keynode *q=NULL;
+
+ arg = skipspace(arg);
+ if (!*arg)
+ return;
+
+ if ((q = *lookup_key(arg)))
+ q->funct(q->call_data);
+ else {
+ PRINTF("#no such key: `%s'\n", arg);
+ }
+}
+
+static void cmd_keyedit __P1 (char *,arg)
+{
+ int function;
+ char *param;
+
+ arg = skipspace(arg);
+ if (!*arg)
+ return;
+
+ if ((function = lookup_edit_name(arg, &param)))
+ internal_functions[function].funct(param);
+ else {
+ PRINTF("#no such editing function: `%s'\n", arg);
+ }
+}
+
+static void cmd_map __P1 (char *,arg)
+{
+ arg = skipspace(arg);
+ if (!*arg) /* show map */
+ map_show();
+ else if (*arg == '-') /* retrace steps without walking */
+ map_retrace(atoi(arg + 1), 0);
+ else
+ map_walk(arg, 1, 1);
+}
+
+static void cmd_retrace __P1 (char *,arg)
+{
+ map_retrace(atoi(arg), 1);
+}
+
+static void cmd_mark __P1 (char *,arg)
+{
+ if (!*arg)
+ show_marks();
+ else
+ parse_mark(arg);
+}
+
+static void cmd_nice __P1 (char *,arg)
+{
+ int nnice = a_nice;
+ arg = skipspace(arg);
+ if (!*arg) {
+ PRINTF("#nice: %d\n", a_nice);
+ return;
+ }
+ if (isdigit(*arg)) {
+ a_nice = 0;
+ while (isdigit(*arg)) {
+ a_nice *= 10;
+ a_nice += *arg++ - '0';
+ }
+ }
+ else if (*arg++=='(') {
+ long buf;
+ int type;
+
+ type = evall(&buf, &arg);
+ if (!REAL_ERROR && type!=TYPE_NUM)
+ error=NO_NUM_VALUE_ERROR;
+ else if (!REAL_ERROR && *arg++ != ')')
+ error=MISSING_PAREN_ERROR;
+ if (REAL_ERROR) {
+ PRINTF("#nice: ");
+ print_error(error);
+ return;
+ }
+ a_nice = (int)buf;
+ if (a_nice<0)
+ a_nice = 0;
+ }
+ arg = skipspace(arg);
+ if (*arg) {
+ parse_instruction(arg, 0, 0, 1);
+ a_nice = nnice;
+ }
+}
+
+static void cmd_prefix __P1 (char *,arg)
+{
+ strcpy(prefixstr, arg);
+ if (echo_int) {
+ PRINTF("#prefix %s.\n", *arg ? "set" : "cleared");
+ }
+}
+
+static void cmd_quote __P1 (char *,arg)
+{
+ arg = skipspace(arg);
+ if (!*arg)
+ verbatim ^= 1;
+ else if (!strcmp(arg, "on"))
+ verbatim = 1;
+ else if (!strcmp(arg, "off"))
+ verbatim = 0;
+ if (echo_int) {
+ PRINTF("#%s mode.\n", verbatim ? "verbatim" : "normal");
+ }
+}
+
+/*
+ * change the escape sequence of an existing binding
+ */
+static void cmd_rebind __P1 (char *,arg)
+{
+ parse_rebind(arg);
+}
+
+static void cmd_rebindall __P1 (char *,arg)
+{
+ keynode *kp;
+ char *seq;
+
+ for (kp = keydefs; kp; kp = kp->next) {
+ seq = kp->sequence;
+ if (kp->seqlen == 1 && seq[0] < ' ')
+ ;
+ else if (kp->seqlen == 2 && seq[0] == '\033' && isalnum(seq[1]))
+ ;
+ else {
+ parse_rebind(kp->name);
+ if (error)
+ break;
+ }
+ }
+}
+
+static void cmd_rebindALL __P1 (char *,arg)
+{
+ keynode *kp;
+
+ for (kp = keydefs; kp; kp = kp->next) {
+ parse_rebind(kp->name);
+ if (error)
+ break;
+ }
+}
+
+static void cmd_reset __P1 (char *,arg)
+{
+ char all = 0;
+ arg = skipspace(arg);
+ if (!*arg) {
+ PRINTF("#reset: must specify one of:\n");
+ tty_puts(" alias, action, bind, in (or at), mark, prompt, var, all.\n");
+ return;
+ }
+ all = !strcmp(arg, "all");
+ if (all || !strcmp(arg, "alias")) {
+ int n;
+ for (n = 0; n < MAX_HASH; n++) {
+ while (aliases[n])
+ delete_aliasnode(&aliases[n]);
+ }
+ if (!all)
+ return;
+ }
+ if (all || !strcmp(arg, "action")) {
+ while (actions)
+ delete_actionnode(&actions);
+ if (!all)
+ return;
+ }
+ if (all || !strcmp(arg, "bind")) {
+ while (keydefs)
+ delete_keynode(&keydefs);
+ tty_add_initial_binds();
+ tty_add_walk_binds();
+ if (!all)
+ return;
+ }
+ if (all || !strcmp(arg, "in") || !strcmp(arg, "at")) {
+ while (delays)
+ delete_delaynode(&delays);
+ while (dead_delays)
+ delete_delaynode(&dead_delays);
+ if (!all)
+ return;
+ }
+ if (all || !strcmp(arg, "mark")) {
+ while (markers)
+ delete_marknode(&markers);
+ if (!all)
+ return;
+ }
+ if (all || !strcmp(arg, "prompt")) {
+ while (prompts)
+ delete_promptnode(&prompts);
+ if (!all)
+ return;
+ }
+ if (all || !strcmp(arg, "var")) {
+ int n;
+ varnode **first;
+
+ for (n = 0; n < MAX_HASH; n++) {
+ while (named_vars[0][n])
+ delete_varnode(&named_vars[0][n], 0);
+ first = &named_vars[1][n];
+ while (*first) {
+ if (is_permanent_variable(*first))
+ first = &(*first)->next;
+ else
+ delete_varnode(first, 1);
+ }
+ }
+
+ for (n = 0; n < NUMVAR; n++) {
+ *var[n].num = 0;
+ ptrdel(*var[n].str);
+ *var[n].str = NULL;
+ }
+ if (!all)
+ return;
+ }
+}
+
+static void cmd_snoop __P1 (char *,arg)
+{
+ if (!*arg) {
+ PRINTF("#snoop: which connection?\n");
+ } else
+ tcp_togglesnoop(arg);
+}
+
+static void cmd_stop __P1 (char *,arg)
+{
+ delaynode *dying;
+
+ if (delays)
+ update_now();
+
+ while (delays) {
+ dying = delays;
+ delays = dying->next;
+ dying->when.tv_sec = now.tv_sec;
+ dying->when.tv_usec = now.tv_usec;
+ dying->next = dead_delays;
+ dead_delays = dying;
+ }
+ if (echo_int) {
+ PRINTF("#all delayed labels are now disabled.\n");
+ }
+}
+
+static void cmd_time __P1 (char *,arg)
+{
+ struct tm *s;
+ char buf[BUFSIZE];
+
+ update_now();
+ s = localtime((time_t *)&now.tv_sec);
+ (void)strftime(buf, BUFSIZE - 1, "%a, %d %b %Y %H:%M:%S", s);
+ PRINTF("#current time is %s\n", buf);
+}
+
+static void cmd_ver __P1 (char *,arg)
+{
+ printver();
+}
+
+static void cmd_emulate __P1 (char *,arg)
+{
+ char kind;
+ FILE *fp;
+ long start, end, i = 1;
+ int len;
+ ptr pbuf = (ptr)0;
+
+ arg = redirect(arg, &pbuf, &kind, "emulate", 0, &start, &end);
+ if (REAL_ERROR || !arg)
+ return;
+
+ if (kind) {
+ char buf[BUFSIZE];
+
+ fp = (kind == '!') ? popen(arg, "r") : fopen(arg, "r");
+ if (!fp) {
+ PRINTF("#emulate: #error opening `%s'\n", arg);
+ print_error(error=SYNTAX_ERROR);
+ ptrdel(pbuf);
+ return;
+ }
+ status(-1); /* we're pretending we got something from the MUD */
+ while (!error && (!start || i<=end) && fgets(buf, BUFSIZE, fp))
+ if (!start || i++>=start)
+ process_remote_input(buf, strlen(buf));
+
+ if (kind == '!') pclose(fp); else fclose(fp);
+ } else {
+ status(-1); /* idem */
+ /* WARNING: no guarantee there is space! */
+ arg[len = strlen(arg)] = '\n';
+ arg[++len] = '\0';
+ process_remote_input(arg, len);
+ }
+ ptrdel(pbuf);
+}
+
+static void cmd_eval __P1 (char *,arg)
+{
+ arg = skipspace(arg);
+ if (*arg=='(') {
+ arg++;
+ (void)evaln(&arg);
+ if (*arg != ')') {
+ PRINTF("#(): ");
+ print_error(error=MISSING_PAREN_ERROR);
+ }
+ }
+ else {
+ PRINTF("#(): ");
+ print_error(error=MISMATCH_PAREN_ERROR);
+ }
+}
+
+static void cmd_exe __P1 (char *,arg)
+{
+ char kind;
+ long start, end, i = 1;
+ FILE *fp;
+ ptr pbuf = (ptr)0;
+
+ arg = redirect(arg, &pbuf, &kind, "exe", 0, &start, &end);
+ if (REAL_ERROR || !arg)
+ return;
+
+ if (kind) {
+ char buf[BUFSIZE];
+
+ fp = (kind == '!') ? popen(arg, "r") : fopen(arg, "r");
+ if (!fp) {
+ PRINTF("#exe: #error opening `%s'\n", arg);
+ error = SYNTAX_ERROR;
+ ptrdel(pbuf);
+ return;
+ }
+ while (!error && (!start || i<=end) && fgets(buf, BUFSIZE, fp))
+ if (!start || i++>=start) {
+ buf[strlen(buf)-1] = '\0';
+ parse_user_input(buf, 0);
+ }
+
+ if (kind == '!') pclose(fp); else fclose(fp);
+ } else
+ parse_user_input(arg, 0);
+ ptrdel(pbuf);
+}
+
+static void cmd_print __P1 (char *,arg)
+{
+ char kind;
+ long start, end, i = 1;
+ FILE *fp;
+ ptr pbuf = (ptr)0;
+
+ clear_input_line(opt_compact);
+
+ if (!*arg) {
+ smart_print(*VAR[0].str ? ptrdata(*VAR[0].str) : (char *)"", 1);
+ return;
+ }
+
+ arg = redirect(arg, &pbuf, &kind, "print", 1, &start, &end);
+ if (REAL_ERROR || !arg)
+ return;
+
+ if (kind) {
+ char buf[BUFSIZE];
+ fp = (kind == '!') ? popen(arg, "r") : fopen(arg, "r");
+ if (!fp) {
+ PRINTF("#print: #error opening `%s'\n", arg);
+ error=SYNTAX_ERROR;
+ ptrdel(pbuf);
+ return;
+ }
+ while (!error && (!start || i <= end) && fgets(buf, BUFSIZE, fp))
+ if (!start || i++>=start)
+ tty_puts(buf);
+ tty_putc('\n');
+
+ if (kind == '!') pclose(fp); else fclose(fp);
+ } else
+ smart_print(arg, 1);
+ ptrdel(pbuf);
+}
+
+static void cmd_send __P1 (char *,arg)
+{
+ char *newline, kind;
+ long start, end, i = 1;
+ FILE *fp;
+ ptr pbuf = (ptr)0;
+
+ arg = redirect(arg, &pbuf, &kind, "send", 0, &start, &end);
+ if (REAL_ERROR ||!arg)
+ return;
+
+ if (kind) {
+ char buf[BUFSIZE];
+ fp = (kind == '!') ? popen(arg, "r") : fopen(arg, "r");
+ if (!fp) {
+ PRINTF("#send: #error opening `%s'\n", arg);
+ error = SYNTAX_ERROR;
+ ptrdel(pbuf);
+ return;
+ }
+ while (!error && (!start || i<=end) && fgets(buf, BUFSIZE, fp)) {
+ if ((newline = strchr(buf, '\n')))
+ *newline = '\0';
+
+ if (!start || i++>=start) {
+ if (echo_ext) {
+ PRINTF("[%s]\n", buf);
+ }
+ tcp_write(tcp_fd, buf);
+ }
+ }
+ if (kind == '!') pclose(fp); else fclose(fp);
+ } else {
+ if (echo_ext) {
+ PRINTF("[%s]\n", arg);
+ }
+ tcp_write(tcp_fd, arg);
+ }
+ ptrdel(pbuf);
+}
+
+static void cmd_rawsend __P1 (char *,arg)
+{
+ char *tmp = skipspace(arg);
+
+ if (*tmp=='(') {
+ ptr pbuf = (ptr)0;
+ arg = tmp + 1;
+ (void)evalp(&pbuf, &arg);
+ if (REAL_ERROR) {
+ print_error(error);
+ ptrdel(pbuf);
+ } else if (pbuf)
+ tcp_raw_write(tcp_fd, ptrdata(pbuf), ptrlen(pbuf));
+ } else {
+ int len;
+ if ((len = memunescape(arg, strlen(arg))))
+ tcp_raw_write(tcp_fd, arg, len);
+ }
+}
+
+static void cmd_rawprint __P1 (char *,arg)
+{
+ char *tmp = skipspace(arg);
+
+ if (*tmp=='(') {
+ ptr pbuf = (ptr)0;
+ arg = tmp + 1;
+ (void)evalp(&pbuf, &arg);
+ if (REAL_ERROR) {
+ print_error(error);
+ ptrdel(pbuf);
+ } else if (pbuf)
+ tty_raw_write(ptrdata(pbuf), ptrlen(pbuf));
+ } else {
+ int len;
+ if ((len = memunescape(arg, strlen(arg))))
+ tty_raw_write(arg, len);
+ }
+}
+
+
+static void cmd_write __P1 (char *,arg)
+{
+ ptr p1 = (ptr)0, p2 = (ptr)0;
+ char *tmp = skipspace(arg), kind;
+ FILE *fp;
+
+ kind = *tmp;
+ if (kind == '!' || kind == '>')
+ arg = ++tmp;
+ else
+ kind = 0;
+
+ if (*tmp=='(') {
+ arg = tmp + 1;
+ (void)evalp(&p1, &arg);
+ if (REAL_ERROR)
+ goto write_cleanup;
+
+ if (*arg == CMDSEP) {
+ arg++;
+ (void)evalp(&p2, &arg);
+ if (!REAL_ERROR && !p2)
+ error = NO_STRING_ERROR;
+ if (REAL_ERROR)
+ goto write_cleanup;
+ } else {
+ PRINTF("#write: ");
+ error=SYNTAX_ERROR;
+ goto write_cleanup;
+ }
+ if (*arg != ')') {
+ PRINTF("#write: ");
+ error=MISSING_PAREN_ERROR;
+ goto write_cleanup;
+ }
+ arg = ptrdata(p2);
+
+ fp = (kind == '!') ? popen(arg, "w") : fopen(arg, kind ? "w" : "a");
+ if (!fp) {
+ PRINTF("#write: #error opening `%s'\n", arg);
+ error=SYNTAX_ERROR;
+ goto write_cleanup2;
+ }
+ fprintf(fp, "%s\n", p1 ? ptrdata(p1) : (char *)"");
+ fflush(fp);
+ if (kind == '!') pclose(fp); else fclose(fp);
+ } else {
+ PRINTF("#write: ");
+ error=MISMATCH_PAREN_ERROR;
+ }
+
+write_cleanup:
+ if (REAL_ERROR)
+ print_error(error);
+write_cleanup2:
+ ptrdel(p1);
+ ptrdel(p2);
+}
+
+static void cmd_var __P1 (char *,arg)
+{
+ char *buf, *expr, *tmp, kind, type, right = 0, deleting = 0;
+ varnode **p_named_var = NULL, *named_var = NULL;
+ FILE *fp;
+ long start, end, i = 1;
+ int len, idx;
+ ptr pbuf = (ptr)0;
+
+ arg = skipspace(arg);
+ expr = first_regular(arg, '=');
+
+ if (*expr) {
+ *expr++ = '\0'; /* skip the = */
+ if (!*expr)
+ deleting = 1;
+ else {
+ right = 1;
+ if (*expr == ' ')
+ expr++;
+ }
+ }
+
+ if (*arg == '$')
+ type = TYPE_TXT_VAR;
+ else if (*arg == '@')
+ type = TYPE_NUM_VAR;
+ else if (*arg) {
+ print_error(error=INVALID_NAME_ERROR);
+ return;
+ } else {
+ show_vars();
+ return;
+ }
+
+ kind = *++arg;
+ if (isalpha(kind) || kind == '_') {
+ /* found a named variable */
+ tmp = arg;
+ while (*tmp && (isalnum(*tmp) || *tmp == '_'))
+ tmp++;
+ if (*tmp) {
+ print_error(error=INVALID_NAME_ERROR);
+ return;
+ }
+ kind = type==TYPE_TXT_VAR ? 1 : 0;
+ p_named_var = lookup_varnode(arg, kind);
+ if (!*p_named_var) {
+ /* it doesn't (yet) exist */
+ if (!deleting) {
+ /* so create it */
+ named_var = add_varnode(arg, kind);
+ if (REAL_ERROR)
+ return;
+ if (echo_int) {
+ PRINTF("#new variable: `%s'\n", arg - 1);
+ }
+ } else {
+ print_error(error=UNDEFINED_VARIABLE_ERROR);
+ return;
+ }
+ } else
+ /* it exists, hold on */
+ named_var = *p_named_var;
+
+ idx = named_var->index;
+ } else {
+ /* not a named variable, may be
+ * an unnamed variable or an expression */
+ kind = type==TYPE_TXT_VAR ? 1 : 0;
+ tmp = skipspace(arg);
+ if (*tmp == '(') {
+ /* an expression */
+ arg = tmp+1;
+ idx = evalp(&pbuf, &arg);
+ if (!REAL_ERROR && idx != TYPE_TXT)
+ error=NO_STRING_ERROR;
+ if (REAL_ERROR) {
+ PRINTF("#var: ");
+ print_error(error);
+ ptrdel(pbuf);
+ return;
+ }
+ if (pbuf)
+ buf = ptrdata(pbuf);
+ else
+ buf = "";
+ if (isdigit(*buf)) {
+ idx = atoi(buf);
+ if (idx < -NUMVAR || idx >= NUMPARAM) {
+ print_error(error=OUT_RANGE_ERROR);
+ ptrdel(pbuf);
+ return;
+ }
+ } else {
+ if (!(named_var = *lookup_varnode(buf, kind))) {
+ if (!deleting) {
+ named_var = add_varnode(buf, kind);
+ if (REAL_ERROR) {
+ print_error(error);
+ ptrdel(pbuf);
+ return;
+ }
+ if (echo_int) {
+ PRINTF("#new variable: %c%s\n", kind
+ ? '$' : '@', buf);
+ }
+ } else {
+ print_error(error=UNDEFINED_VARIABLE_ERROR);
+ ptrdel(pbuf);
+ return;
+ }
+ }
+ idx = named_var->index;
+ }
+ } else {
+ /* an unnamed var */
+ long buf2;
+
+ idx = evall(&buf2, &arg);
+ if (!REAL_ERROR && idx != TYPE_NUM)
+ error=NO_STRING_ERROR;
+ if (REAL_ERROR) {
+ PRINTF("#var: ");
+ print_error(error);
+ return;
+ }
+ idx = (int)buf2;
+ if (idx < -NUMVAR || idx >= NUMPARAM) {
+ print_error(error=OUT_RANGE_ERROR);
+ return;
+ }
+ /* ok, it's an unnamed var */
+ }
+ }
+
+
+ if (type == TYPE_TXT_VAR && right && !*VAR[idx].str) {
+ /* create it */
+ *VAR[idx].str = ptrnew(PARAMLEN);
+ if (MEM_ERROR) {
+ print_error(error);
+ ptrdel(pbuf);
+ return;
+ }
+ }
+
+ if (deleting) {
+ /* R.I.P. named variables */
+ if (named_var) {
+ if (is_permanent_variable(named_var)) {
+ PRINTF("#cannot delete variable: `%s'\n", arg - 1);
+ } else {
+ delete_varnode(p_named_var, kind);
+ if (echo_int) {
+ PRINTF("#deleted variable: `%s'\n", arg - 1);
+ }
+ }
+ } else if ((type = TYPE_TXT_VAR)) {
+ /* R.I.P. unnamed variables */
+ if (*VAR[idx].str) {
+ if (idx < 0) {
+ ptrdel(*VAR[idx].str);
+ *VAR[idx].str = 0;
+ } else
+ ptrzero(*VAR[idx].str);
+ }
+ } else
+ *VAR[idx].num = 0;
+ ptrdel(pbuf);
+ return;
+ } else if (!right) {
+ /* no right-hand expression, just show */
+ if (named_var) {
+ if (type == TYPE_TXT_VAR) {
+ pbuf = ptrescape(pbuf, *VAR[idx].str, 0);
+ if (REAL_ERROR) {
+ print_error(error);
+ ptrdel(pbuf);
+ return;
+ }
+ sprintf(inserted_next, "#($%.*s = \"%.*s\")",
+ BUFSIZE - 10, named_var->name,
+ BUFSIZE - (int)strlen(named_var->name) - 10,
+ pbuf ? ptrdata(pbuf) : (char *)"");
+ } else {
+ sprintf(inserted_next, "#(@%.*s = %ld)",
+ BUFSIZE - 8, named_var->name,
+ *VAR[idx].num);
+ }
+ } else {
+ if (type == TYPE_TXT_VAR) {
+ pbuf = ptrescape(pbuf, *VAR[idx].str, 0);
+ sprintf(inserted_next, "#($%d = \"%.*s\")", idx,
+ BUFSIZE - INTLEN - 10,
+ pbuf ? ptrdata(pbuf) : (char *)"");
+ } else {
+ sprintf(inserted_next, "#(@%d = %ld)", idx,
+ *VAR[idx].num);
+ }
+ }
+ ptrdel(pbuf);
+ return;
+ }
+
+ /* only case left: assign a value to a variable */
+ arg = redirect(expr, &pbuf, &kind, "var", 1, &start, &end);
+ if (REAL_ERROR || !arg)
+ return;
+
+ if (kind) {
+ char buf2[BUFSIZE];
+ fp = (kind == '!') ? popen(arg, "r") : fopen(arg, "r");
+ if (!fp) {
+ PRINTF("#var: #error opening `%s'\n", arg);
+ error=SYNTAX_ERROR;
+ ptrdel(pbuf);
+ return;
+ }
+ len = 0;
+ i = 1;
+ while (!error && (!start || i<=end) && fgets(buf2+len, BUFSIZE-len, fp))
+ if (!start || i++>=start)
+ len += strlen(buf2 + len);
+
+ if (kind == '!') pclose(fp); else fclose(fp);
+ if (len>PARAMLEN)
+ len = PARAMLEN;
+ buf2[len] = '\0';
+ arg = buf2;
+ }
+
+ if (type == TYPE_NUM_VAR) {
+ arg = skipspace(arg);
+ type = 1;
+ len = 0;
+
+ if (*arg == '-')
+ arg++, type = -1;
+ else if (*arg == '+')
+ arg++;
+
+ if (isdigit(kind=*arg)) while (isdigit(kind)) {
+ len*=10;
+ len+=(kind-'0');
+ kind=*++arg;
+ }
+ else {
+ PRINTF("#var: ");
+ print_error(error=NO_NUM_VALUE_ERROR);
+ }
+ *VAR[idx].num = len * type;
+ }
+ else {
+ *VAR[idx].str = ptrmcpy(*VAR[idx].str, arg, strlen(arg));
+ if (MEM_ERROR)
+ print_error(error);
+ }
+ ptrdel(pbuf);
+}
+
+static void cmd_setvar __P1 (char *,arg)
+{
+ char *name;
+ int i, func = 0; /* show */
+ long buf;
+
+ name = arg = skipspace(arg);
+ arg = first_regular(arg, '=');
+ if (*arg) {
+ *arg++ = '\0';
+ if (*arg) {
+ func = 1; /* set */
+ if (*arg == '(') {
+ arg++;
+ i = evall(&buf, &arg);
+ if (!REAL_ERROR && i != TYPE_NUM)
+ error=NO_NUM_VALUE_ERROR;
+ else if (!REAL_ERROR && *arg != ')')
+ error=MISSING_PAREN_ERROR;
+ } else
+ buf = strtol(arg, NULL, 0);
+ } else
+ buf = 0;
+
+ if (REAL_ERROR) {
+ PRINTF("#setvar: ");
+ print_error(error);
+ return;
+ }
+ }
+
+ i = strlen(name);
+ if (i && !strncmp(name, "timer", i)) {
+ vtime t;
+ update_now();
+ if (func == 0)
+ sprintf(inserted_next, "#setvar timer=%ld",
+ diff_vtime(&now, &ref_time));
+ else {
+ t.tv_usec = ((-buf) % mSEC_PER_SEC) * uSEC_PER_mSEC;
+ t.tv_sec = (-buf) / mSEC_PER_SEC;
+ ref_time.tv_usec = now.tv_usec;
+ ref_time.tv_sec = now.tv_sec;
+ add_vtime(&ref_time, &t);
+ }
+ }
+ else if (i && !strncmp(name, "lines", i)) {
+ if (func == 0)
+ sprintf(inserted_next, "#setvar lines=%d", lines);
+ else {
+ if (buf > 0)
+ lines = (int)buf;
+ if (echo_int) {
+ PRINTF("#setvar: lines=%d\n", lines);
+ }
+ }
+ }
+ else if (i && !strncmp(name, "mem", i)) {
+ if (func == 0)
+ sprintf(inserted_next, "#setvar mem=%d", limit_mem);
+ else {
+ if (buf == 0 || buf >= PARAMLEN)
+ limit_mem = buf <= INT_MAX ? (int)buf : INT_MAX;
+ if (echo_int) {
+ PRINTF("#setvar: mem=%d%s\n", limit_mem,
+ limit_mem ? "" : " (unlimited)");
+ }
+ }
+ }
+ else if (i && !strncmp(name, "buffer", i)) {
+ if (func == 0)
+ sprintf(inserted_next, "#setvar buffer=%d", log_getsize());
+ else
+ log_resize(buf);
+ } else {
+ update_now();
+ PRINTF("#setvar buffer=%d\n#setvar lines=%d\n#setvar mem=%d\n#setvar timer=%ld\n",
+ log_getsize(), lines, limit_mem, diff_vtime(&now, &ref_time));
+ }
+}
+
+static void cmd_if __P1 (char *,arg)
+{
+ long buf;
+ int type;
+
+ arg = skipspace(arg);
+ if (*arg!='(') {
+ PRINTF("#if: ");
+ print_error(error=MISMATCH_PAREN_ERROR);
+ return;
+ }
+ arg++; /* skip the '(' */
+
+ type = evall(&buf, &arg);
+ if (!REAL_ERROR) {
+ if (type!=TYPE_NUM)
+ error=NO_NUM_VALUE_ERROR;
+ if (*arg != ')')
+ error=MISSING_PAREN_ERROR;
+ else { /* skip the ')' */
+ if (*++arg == ' ')
+ arg++;
+ }
+ }
+ if (REAL_ERROR) {
+ PRINTF("#if: ");
+ print_error(error);
+ return;
+ }
+
+ if (buf)
+ (void)parse_instruction(arg, 0, 0, 1);
+ else {
+ arg = get_next_instr(arg);
+ if (!strncmp(arg = skipspace(arg), "#else ", 6))
+ (void)parse_instruction(arg + 6, 0, 0, 1);
+ }
+}
+
+static void cmd_for __P1 (char *,arg)
+{
+ int type = TYPE_NUM, loop=MAX_LOOP;
+ long buf;
+ char *check, *tmp, *increm = 0;
+
+ arg = skipspace(arg);
+ if (*arg != '(') {
+ PRINTF("#for: ");
+ print_error(error=MISMATCH_PAREN_ERROR);
+ return;
+ }
+ push_params();
+ if (REAL_ERROR)
+ return;
+
+ arg = skipspace(arg + 1); /* skip the '(' */
+ if (*arg != CMDSEP)
+ (void)evaln(&arg); /* execute <init> */
+
+ check = arg + 1;
+
+ if (REAL_ERROR)
+ ;
+ else if (*arg != CMDSEP) {
+ PRINTF("#for: ");
+ print_error(error=MISSING_SEPARATOR_ERROR);
+ }
+ else while (!error && loop
+ && (increm=check, (type = evall(&buf, &increm)) == TYPE_NUM
+ && !error && *increm == CMDSEP && buf)) {
+
+ tmp = first_regular(increm + 1, ')');
+ if (*tmp)
+ (void)parse_instruction(tmp + 1, 1, 1, 1);
+ else {
+ PRINTF("#for: ");
+ print_error(error=MISSING_PAREN_ERROR);
+ }
+
+ if (!error) {
+ tmp = increm + 1;
+ if (*tmp != ')')
+ (void)evaln(&tmp);
+ }
+
+ loop--;
+ }
+ if (REAL_ERROR)
+ ;
+ else if (increm && *increm != CMDSEP)
+ error=MISSING_SEPARATOR_ERROR;
+ else if (!loop)
+ error=MAX_LOOP_ERROR;
+ else if (type != TYPE_NUM)
+ error=NO_NUM_VALUE_ERROR;
+ if (REAL_ERROR) {
+ PRINTF("#for: ");
+ print_error(error);
+ }
+ if (error!=DYN_STACK_UND_ERROR && error!=DYN_STACK_OV_ERROR)
+ pop_params();
+}
+
+static void cmd_while __P1 (char *,arg)
+{
+ int type = TYPE_NUM, loop=MAX_LOOP;
+ long buf;
+ char *check, *tmp;
+
+ arg = skipspace(arg);
+ if (!*arg) {
+ PRINTF("#while: ");
+ print_error(error=MISMATCH_PAREN_ERROR);
+ return;
+ }
+ push_params();
+
+ check = ++arg; /* skip the '(' */
+ while (!error && loop
+ && (arg=check, (type = evall(&buf, &arg)) == TYPE_NUM &&
+ !error && *arg == ')' && buf)) {
+
+ if (*(tmp = arg + 1) == ' ') /* skip the ')' */
+ tmp++;
+ if (*tmp)
+ (void)parse_instruction(tmp, 1, 1, 1);
+ loop--;
+ }
+ if (REAL_ERROR)
+ ;
+ else if (*arg != ')')
+ error=MISSING_PAREN_ERROR;
+ else if (!loop)
+ error=MAX_LOOP_ERROR;
+ else if (type != TYPE_NUM)
+ error=NO_NUM_VALUE_ERROR;
+ if (REAL_ERROR) {
+ PRINTF("#while: ");
+ print_error(error);
+ }
+ if (error!=DYN_STACK_UND_ERROR && error!=DYN_STACK_OV_ERROR)
+ pop_params();
+}
+
+static void cmd_capture __P1 (char *,arg)
+{
+ arg = skipspace(arg);
+
+ if (!*arg) {
+ if (capturefile) {
+ log_flush();
+ fclose(capturefile);
+ capturefile = NULL;
+ if (echo_int) {
+ PRINTF("#end of capture to file.\n");
+ }
+ } else {
+ PRINTF("#capture to what file?\n");
+ }
+ } else {
+ if (capturefile) {
+ PRINTF("#capture already active.\n");
+ } else {
+ short append = 0;
+ /* Append to log file, if the name starts with '>' */
+ if (*arg == '>') {
+ arg++;
+ append = 1;
+ }
+ if ((capturefile = fopen(arg, (append) ? "a" : "w")) == NULL) {
+ PRINTF("#error writing file `%s'\n", arg);
+ } else if (echo_int) {
+ PRINTF("#capture to `%s' active, `#capture' ends.\n", arg);
+ }
+ }
+ }
+}
+
+static void cmd_movie __P1 (char *,arg)
+{
+ arg = skipspace(arg);
+
+ if (!*arg) {
+ if (moviefile) {
+ log_flush();
+ fclose(moviefile);
+ moviefile = NULL;
+ if (echo_int) {
+ PRINTF("#end of movie to file.\n");
+ }
+ } else {
+ PRINTF("#movie to what file?\n");
+ }
+ } else {
+ if (moviefile) {
+ PRINTF("#movie already active.\n");
+ } else {
+ if ((moviefile = fopen(arg, "w")) == NULL) {
+ PRINTF("#error writing file `%s'\n", arg);
+ } else {
+ if (echo_int) {
+ PRINTF("#movie to `%s' active, `#movie' ends.\n", arg);
+ }
+ update_now();
+ movie_last = now;
+ log_clearsleep();
+ }
+ }
+ }
+}
+
+static void cmd_record __P1 (char *,arg)
+{
+ arg = skipspace(arg);
+
+ if (!*arg) {
+ if (recordfile) {
+ fclose(recordfile);
+ recordfile = NULL;
+ if (echo_int) {
+ PRINTF("#end of record to file.\n");
+ }
+ } else {
+ PRINTF("#record to what file?\n");
+ }
+ } else {
+ if (recordfile) {
+ PRINTF("#record already active.\n");
+ } else {
+ if ((recordfile = fopen(arg, "w")) == NULL) {
+ PRINTF("#error writing file `%s'\n", arg);
+ } else if (echo_int) {
+ PRINTF("#record to `%s' active, `#record' ends.\n", arg);
+ }
+ }
+ }
+}
+
+static void cmd_edit __P1 (char *,arg)
+{
+ editsess *sp;
+
+ if (edit_sess) {
+ for (sp = edit_sess; sp; sp = sp->next) {
+ PRINTF("# %s (%u)\n", sp->descr, sp->key);
+ }
+ } else {
+ PRINTF("#no active editors.\n");
+ }
+}
+
+static void cmd_cancel __P1 (char *,arg)
+{
+ editsess *sp;
+
+ if (!edit_sess) {
+ PRINTF("#no editing sessions to cancel.\n");
+ } else {
+ if (*arg) {
+ for (sp = edit_sess; sp; sp = sp->next)
+ if (strtoul(arg, NULL, 10) == sp->key) {
+ cancel_edit(sp);
+ break;
+ }
+ if (!sp) {
+ PRINTF("#unknown editing session %d\n", atoi(arg));
+ }
+ } else {
+ if (edit_sess->next) {
+ PRINTF("#several editing sessions active, use #cancel <number>\n");
+ } else
+ cancel_edit(edit_sess);
+ }
+ }
+}
+
+static void cmd_net __P1 (char *,arg)
+{
+ PRINTF("#received from host: %ld chars, sent to host: %ld chars.\n",
+ received, sent);
+}
+
+
+#ifndef CLOCKS_PER_SEC
+# define CLOCKS_PER_SEC uSEC_PER_SEC
+#endif
+/* hope it works.... */
+
+static void cmd_cpu __P1 (char *,arg)
+{
+ float f, l;
+ update_now();
+ f = (float)((cpu_clock = clock()) - start_clock) / (float)CLOCKS_PER_SEC;
+ l = (float)(diff_vtime(&now, &start_time)) / (float)mSEC_PER_SEC;
+ PRINTF("#CPU time used: %.3f sec. (%.2f%%)\n", f,
+ (l > 0 && l > f) ? f * 100.0 / l : 100.0);
+}
+
+void show_stat __P0 (void)
+{
+ cmd_net(NULL);
+ cmd_cpu(NULL);
+}
+
+#ifdef BUG_TELNET
+static void cmd_color __P1 (char *,arg)
+{
+ int attrcode;
+
+ arg = skipspace(arg);
+ if (!*arg) {
+ strcpy(tty_modenorm, tty_modenormbackup);
+ tty_puts(tty_modenorm);
+ if (echo_int) {
+ PRINTF("#standard color cleared.\n");
+ }
+ return;
+ }
+
+ attrcode = parse_attributes(arg);
+ if (attrcode == -1) {
+ PRINTF("#invalid attribute syntax.\n");
+ if (echo_int)
+ show_attr_syntax();
+ } else {
+ int bg = BACKGROUND(attrcode), fg = FOREGROUND(attrcode);
+ if (fg >= COLORS || bg >= COLORS) {
+ PRINTF("#please specify foreground and background colors.\n");
+ } else {
+ sprintf(tty_modenorm, "\033[;%c%d;%s%dm",
+ fg<LOWCOLORS ? '3' : '9', fg % LOWCOLORS,
+ bg<LOWCOLORS ? "4" :"10", bg % LOWCOLORS);
+ tty_puts(tty_modenorm);
+ if (echo_int) {
+ PRINTF("#standard colour set.\n");
+ }
+ }
+ }
+}
+#endif
+
+static void cmd_connect __P1 (char *,arg)
+{
+#ifdef TERM
+ PRINTF("#connect: multiple connections not supported in term version.\n");
+#else
+ char *s1, *s2, *s3 = NULL, *s4 = NULL;
+ int argc = 1;
+
+ if (!*skipspace(arg)) {
+ tcp_show();
+ return;
+ }
+ else {
+ s1 = strtok(arg, " ");
+ s2 = strtok(NULL, " ");
+ if (s2 && *s2) {
+ argc++;
+ s3 = strtok(NULL, " ");
+ if (s3 && *s3) {
+ argc++;
+ s4 = strtok(NULL, " ");
+ if (s4 && *s4)
+ argc++;
+ }
+ }
+ }
+
+ if (argc <= 2) {
+ if (*hostname)
+ tcp_open(s1, s2, hostname, portnumber);
+ else {
+ PRINTF("#connect: no host defined!\n#syntax: #connect session-id [[init-str] [hostname] [port]]\n");
+ }
+ } else if (argc == 3) {
+ if (!*hostname) {
+ my_strncpy(hostname, s2, BUFSIZE-1);
+ portnumber = atoi(s3);
+ }
+ tcp_open(s1, NULL, s2, atoi(s3));
+ } else {
+ if (!*hostname) {
+ my_strncpy(hostname, s3, BUFSIZE-1);
+ portnumber = atoi(s4);
+ }
+ tcp_open(s1, s2, s3, atoi(s4));
+ }
+#endif /* TERM */
+}
+
+
+static void cmd_spawn __P1 (char *,arg)
+{
+ char s[BUFSIZE];
+ if (*(arg = skipspace(arg))) {
+ arg = split_first_word(s, BUFSIZE, arg);
+ if (*arg && *s) {
+ tcp_spawn(s, arg);
+ return;
+ }
+ }
+ PRINTF("#syntax: #spawn connect-id command\n");
+}
+
+static void cmd_zap __P1 (char *,arg)
+{
+ if (!*arg) {
+ PRINTF("#zap: no connection name.\n");
+ } else
+ tcp_close(arg);
+}
+
+static void cmd_qui __P1 (char *,arg)
+{
+ PRINTF("#you have to write '#quit' - no less, to quit!\n");
+}
+
+static void cmd_quit __P1 (char *,arg)
+{
+ if (*arg) { /* no skipspace() here! */
+ PRINTF("#quit: spurious argument?\n");
+ } else
+ exit_powwow();
+}
+
+char *full_options_string = "#option %cexit %chistory %cwords %ccompact %cdebug %cecho %cinfo %ckeyecho %cspeedwalk\n#option %cwrap %cautoprint %creprint %csendsize %cautoclear%s";
+
+static void cmd_option __P1 (char *,arg)
+{
+ if (*(arg = skipspace(arg))) {
+ int len, i, count = 0;
+ static char *str[] = { "exit", "history", "words",
+ "compact", "debug", "echo", "info", "keyecho",
+ "speedwalk", "wrap", "autoprint", "reprint",
+ "sendsize", "autoclear", 0 };
+ static char *varptr[] = { &opt_exit, &opt_history, &opt_words,
+ &opt_compact, &opt_debug, &echo_ext, &echo_int, &echo_key,
+ &opt_speedwalk, &opt_wrap, &opt_autoprint, &opt_reprint,
+ &opt_sendsize, &opt_autoclear, 0 };
+ enum { MODE_ON, MODE_OFF, MODE_TOGGLE, MODE_REP } mode;
+ char buf[BUFSIZE], *p, *varp, c;
+ while ((arg = skipspace(split_first_word(buf, BUFSIZE, arg))), *buf) {
+ c = *(p = buf);
+ switch (c) {
+ case '=': mode = MODE_REP; p++; break;
+ case '+': mode = MODE_ON; p++; break;
+ case '-': mode = MODE_OFF; p++; break;
+ default: mode = MODE_TOGGLE; break;
+ }
+ len = strlen(p);
+ varp = 0;
+ count++;
+ for (i=0; str[i]; i++) {
+ if (strncmp(str[i], p, len) == 0) {
+ varp = varptr[i];
+ break;
+ }
+ }
+ if (!str[i]) {
+ if (strncmp("none", p, len) == 0)
+ continue;
+ else {
+ PRINTF("#syntax: #option [[+|-|=]<name>]\t\twhere <name> is one of:\n\
+exit history words compact debug echo info\n\
+keyecho speedwalk wrap autoprint reprint sendsize autoclear\n");
+ return;
+ }
+ }
+ if (varp) {
+ switch (mode) {
+ case MODE_REP:
+ sprintf(inserted_next, "#option %c", *varp ? '+' : '-');
+ strcat(inserted_next, p);
+ break;
+ case MODE_ON: *varp = 1; break;
+ case MODE_OFF: *varp = 0; break;
+ default: *varp ^= 1; break;
+ }
+ /*
+ * reset the reprint buffer if changing its status
+ */
+ if (varp == &opt_reprint)
+ reprint_clear();
+
+ /* as above, but always print status if
+ * `#option info' alone was typed */
+ if (mode != MODE_REP && !*arg && count==1 &&
+ (echo_int || (mode == MODE_TOGGLE && varp==&echo_int))) {
+ PRINTF("#option %s is now o%s.\n", str[i],
+ *varp ? "n" : "ff");
+ }
+ }
+ }
+ } else {
+ PRINTF(full_options_string,
+ opt_exit ? '+' : '-',
+ opt_history ? '+' : '-',
+ opt_words ? '+' : '-',
+ opt_compact ? '+' : '-',
+ opt_debug ? '+' : '-',
+ echo_ext ? '+' : '-',
+ echo_int ? '+' : '-',
+ echo_key ? '+' : '-',
+ opt_speedwalk ? '+' : '-',
+ opt_wrap ? '+' : '-',
+ opt_autoprint ? '+' : '-',
+ opt_reprint ? '+' : '-',
+ opt_sendsize ? '+' : '-',
+ opt_autoclear ? '+' : '-',
+ "\n");
+ }
+}
+
+static void cmd_file __P1 (char *,arg)
+{
+ arg = skipspace(arg);
+ if (*arg == '=') {
+ set_deffile(++arg);
+ if (echo_int) {
+ if (*arg) {
+ PRINTF("#save-file set to `%s'\n", deffile);
+ } else {
+ PRINTF("#save-file is now undefined.\n");
+ }
+ }
+ } else if (*deffile) {
+ sprintf(inserted_next, "#file =%.*s", BUFSIZE-8, deffile);
+ } else {
+ PRINTF("#save-file not defined.\n");
+ }
+}
+
+static void cmd_save __P1 (char *,arg)
+{
+ arg = skipspace(arg);
+ if (*arg) {
+ set_deffile(arg);
+ if (echo_int) {
+ PRINTF("#save-file set to `%s'\n", deffile);
+ }
+ } else if (!*deffile) {
+ PRINTF("#save-file not defined.\n");
+ return;
+ }
+
+ if (*deffile && save_settings() > 0 && echo_int) {
+ PRINTF("#settings saved to file.\n");
+ }
+}
+
+static void cmd_load __P1 (char *,arg)
+{
+ int res;
+
+ arg = skipspace(arg);
+ if (*arg) {
+ set_deffile(arg);
+ if (echo_int) {
+ PRINTF("#save-file set to `%s'\n", deffile);
+ }
+ }
+ else if (!*deffile) {
+ PRINTF("#save-file not defined.\n");
+ return;
+ }
+
+ res = read_settings();
+
+ if (res > 0) {
+ /* success */
+ if (echo_int) {
+ PRINTF("#settings loaded from file.\n");
+ }
+ } else if (res < 0) {
+ /* critical error */
+ while (keydefs)
+ delete_keynode(&keydefs);
+ tty_add_initial_binds();
+ tty_add_walk_binds();
+ limit_mem = 1048576;
+ PRINTF("#emergency loaded default settings.\n");
+ }
+}
+
+static char *trivial_eval __P3 (ptr *,pbuf, char *,arg, char *,name)
+{
+ char *tmp = skipspace(arg);
+
+ if (!pbuf)
+ return NULL;
+
+ if (*tmp=='(') {
+ arg = tmp + 1;
+ (void)evalp(pbuf, &arg);
+ if (!REAL_ERROR && *arg != ')')
+ error=MISSING_PAREN_ERROR;
+ if (REAL_ERROR) {
+ PRINTF("#%s: ", name);
+ print_error(error);
+ return NULL;
+ }
+ if (*pbuf)
+ arg = ptrdata(*pbuf);
+ else
+ arg = "";
+ }
+ else
+ unescape(arg);
+
+ return arg;
+}
+
+static void cmd_add __P1 (char *,arg)
+{
+ ptr pbuf = (ptr)0;
+ char buf[BUFSIZE];
+
+ arg = trivial_eval(&pbuf, arg, "add");
+ if (!REAL_ERROR)
+ while (*arg) {
+ arg = split_first_word(buf, BUFSIZE, arg);
+ if (strlen(buf) >= MIN_WORDLEN)
+ put_word(buf);
+ }
+ ptrdel(pbuf);
+}
+
+static void cmd_put __P1 (char *,arg)
+{
+ ptr pbuf = (ptr)0;
+ arg = trivial_eval(&pbuf, arg, "put");
+ if (!REAL_ERROR && *arg)
+ put_history(arg);
+ ptrdel(pbuf);
+}
+
+