# include <config.h> # include "/dgd/lib/privilege.h" # undef status # define C_CONTROL 21 # define C_IF 1 # define C_IFNOT 2 # define C_LAND 3 # define C_LOR 4 # define C_WHILE 5 # define C_DO 6 # define C_PROGN 7 # define C_ASSIGN 8 # define C_PLUSEQ 9 # define C_MINEQ 10 # define C_MULTEQ 11 # define C_DIVEQ 12 # define C_MODEQ 13 # define C_LSHIFTEQ 14 # define C_RSHIFTEQ 15 # define C_ANDEQ 16 # define C_XOREQ 17 # define C_OREQ 18 # define C_PLUSPLUS 19 # define C_MINMIN 20 # define C_SSCANF 21 # define C_INDEX 22 # define C_RANGE 23 # define C_CALL_OTHER 24 # define C_NOT 25 # define C_LNOT 26 # define C_NEGATE 27 # define C_MULT 28 # define C_DIV 29 # define C_MOD 30 # define C_PLUS 31 # define C_MIN 32 # define C_LSHIFT 33 # define C_RSHIFT 34 # define C_LESS 35 # define C_LESSEQ 36 # define C_GREATER 37 # define C_GREATEREQ 38 # define C_EQ 39 # define C_NOTEQ 40 # define C_AND 41 # define C_XOR 42 # define C_OR 43 # define C_QUOTE 44 # define C_ADD_ACTION 45 # define C_ADD_VERB 46 # define C_ADD_WORTH 47 # define C_ALL_INVENTORY 48 # define C_ALLOCATE 49 # define C_APPLY 50 # define C_CALL_OUT 51 # define C_CALL_TRACE 52 # define C_CAPITALIZE 53 # define C_CAT 54 # define C_CINDENT 55 # define C_CLEAR_BIT 56 # define C_CLONE_OBJECT 57 # define C_CLOSUREP 58 # define C_COMMAND 59 # define C_CREATE_WIZARD 60 # define C_CREATOR 61 # define C_CRYPT 62 # define C_CTIME 63 # define C_DEEP_INVENTORY 64 # define C_DESTRUCT 65 # define C_DISABLE_COMMANDS 66 # define C_ENABLE_COMMANDS 67 # define C_ENVIRONMENT 68 # define C_ERROR 69 # define C_EXEC 70 # define C_EXPLODE 71 # define C_FILE_NAME 72 # define C_FILE_SIZE 73 # define C_FILTER_ARRAY 74 # define C_FILTER_MAPPING 75 # define C_FIND_CALL_OUT 76 # define C_FIND_LIVING 77 # define C_FIND_OBJECT 78 # define C_FIND_PLAYER 79 # define C_FIRST_INVENTORY 80 # define C_FUNCTION_EXISTS 81 # define C_GET_DIR 82 # define C_GET_EXEC_COST 83 # define C_IMPLODE 84 # define C_INTERACTIVE 85 # define C_INTP 86 # define C_LAMBDA 87 # define C_LIVING 88 # define C_LOCALCMD 89 # define C_LOG_FILE 90 # define C_LOWER_CASE 91 # define C_LS 92 # define C_M_DELETE 93 # define C_M_INDICES 94 # define C_M_SIZEOF 95 # define C_M_VALUES 96 # define C_MAP_ARRAY 97 # define C_MAP_MAPPING 98 # define C_MAPPINGP 99 # define C_MEMBER_ARRAY 100 # define C_MKDIR 101 # define C_MKMAPPING 102 # define C_MOVE_OBJECT 103 # define C_NEXT_INVENTORY 104 # define C_NOTIFY_FAIL 105 # define C_OBJECTP 106 # define C_PARSE_STRING 107 # define C_POINTERP 108 # define C_PRESENT 109 # define C_PREVIOUS_OBJECT 110 # define C_QUERY_HOST_NAME 111 # define C_QUERY_IDLE 112 # define C_QUERY_IP_NAME 113 # define C_QUERY_IP_NUMBER 114 # define C_QUERY_LOAD_AVERAGE 115 # define C_QUERY_SNOOP 116 # define C_QUERY_VERB 117 # define C_RANDOM 118 # define C_READ_BYTES 119 # define C_READ_FILE 120 # define C_REMOVE_CALL_OUT 121 # define C_RENAME 122 # define C_RESTORE_OBJECT 123 # define C_RM 124 # define C_RMDIR 125 # define C_SAVE_OBJECT 126 # define C_SAY 127 # define C_SET_BIT 128 # define C_SET_HEART_BEAT 129 # define C_SET_LIVING_NAME 130 # define C_SET_THIS_PLAYER 131 # define C_SHOUT 132 # define C_SHUTDOWN 133 # define C_SIZEOF 134 # define C_SNOOP 135 # define C_SORT_ARRAY 136 # define C_STATUS 137 # define C_STRINGP 138 # define C_STRLEN 139 # define C_SWAPOUT 140 # define C_TAIL 141 # define C_TELL_OBJECT 142 # define C_TELL_ROOM 143 # define C_TEST_BIT 144 # define C_THIS_OBJECT 145 # define C_THIS_PLAYER 146 # define C_TIME 147 # define C_TRANSFER 148 # define C_UNIQUE_ARRAY 149 # define C_USERS 150 # define C_VERSION 151 # define C_WIZLIST 152 # define C_WRITE 153 # define C_WRITE_BYTES 154 # define C_WRITE_FILE 155 # define MINMAX(min, max) ((min) | ((max) << 8)) # define MIN(c) (minmax[c - 1] & 0xff) # define MAX(c) (minmax[c - 1] >> 8) object command_giver; /* the current player */ string notify_mesg; /* current notify_fail mesg */ string verb; /* the current verb */ mapping players; /* player mapping */ mapping monsters; /* monster mapping */ mapping objects; /* objects mapping */ mapping heart_beats; /* heart_beats mapping */ mapping call_outs; /* call_outs mapping */ mapping codes; /* function to code */ int *minmax; /* min & max # of arguments for functions */ static void reset(int arg) { int i; if (players == 0) { players = ([ ]); monsters = ([ ]); heart_beats = ([ ]); call_outs = ([ ]); codes = ([ "?" : C_IF, "?!" : C_IFNOT, "&&" : C_LAND, "||" : C_LOR, "while" : C_WHILE, "do" : C_DO, "," : C_PROGN, "=" : C_ASSIGN, "+=" : C_PLUSEQ, "-=" : C_MINEQ, "*=" : C_MULTEQ, "/=" : C_DIVEQ, "%=" : C_MODEQ, "<<=" : C_LSHIFTEQ, ">>=" : C_RSHIFTEQ, "&=" : C_ANDEQ, "^=" : C_XOREQ, "|=" : C_OREQ, "++" : C_PLUSPLUS, "--" : C_MINMIN, "sscanf" : C_SSCANF, "[" : C_INDEX, "[.." : C_RANGE, "->" : C_CALL_OTHER, "~" : C_NOT, "!" : C_LNOT, "negate" : C_NEGATE, "*" : C_MULT, "/" : C_DIV, "%" : C_MOD, "+" : C_PLUS, "-" : C_MIN, "<<" : C_LSHIFT, ">>" : C_RSHIFT, "<" : C_LESS, "<=" : C_LESSEQ, ">" : C_GREATER, ">=" : C_GREATEREQ, "==" : C_EQ, "!=" : C_NOTEQ, "&" : C_AND, "^" : C_XOR, "|" : C_OR, "'" : C_QUOTE, "add_action" : C_ADD_ACTION, "add_verb" : C_ADD_VERB, "add_worth" : C_ADD_WORTH, "all_inventory" : C_ALL_INVENTORY, "allocate" : C_ALLOCATE, "apply" : C_APPLY, "call_other" : C_CALL_OTHER, "call_out" : C_CALL_OUT, "call_trace" : C_CALL_TRACE, "capitalize" : C_CAPITALIZE, "cat" : C_CAT, "cindent" : C_CINDENT, "clear_bit" : C_CLEAR_BIT, "clone_object" : C_CLONE_OBJECT, "closurep" : C_CLOSUREP, "command" : C_COMMAND, "create_wizard" : C_CREATE_WIZARD, "creator" : C_CREATOR, "crypt" : C_CRYPT, "ctime" : C_CTIME, "deep_inventory" : C_DEEP_INVENTORY, "destruct" : C_DESTRUCT, "disable_commands": C_DISABLE_COMMANDS, "enable_commands" : C_ENABLE_COMMANDS, "environment" : C_ENVIRONMENT, "error" : C_ERROR, "exec" : C_EXEC, "explode" : C_EXPLODE, "file_name" : C_FILE_NAME, "file_size" : C_FILE_SIZE, "filter_array" : C_FILTER_ARRAY, "filter_mapping" : C_FILTER_MAPPING, "find_call_out" : C_FIND_CALL_OUT, "find_living" : C_FIND_LIVING, "find_object" : C_FIND_OBJECT, "find_player" : C_FIND_PLAYER, "first_inventory" : C_FIRST_INVENTORY, "function_exists" : C_FUNCTION_EXISTS, "get_dir" : C_GET_DIR, "get_exec_cost" : C_GET_EXEC_COST, "implode" : C_IMPLODE, "interactive" : C_INTERACTIVE, "intp" : C_INTP, "lambda" : C_LAMBDA, "living" : C_LIVING, "localcmd" : C_LOCALCMD, "log_file" : C_LOG_FILE, "lower_case" : C_LOWER_CASE, "ls" : C_LS, "m_delete" : C_M_DELETE, "m_indices" : C_M_INDICES, "m_sizeof" : C_M_SIZEOF, "m_values" : C_M_VALUES, "map_array" : C_MAP_ARRAY, "map_mapping" : C_MAP_MAPPING, "mappingp" : C_MAPPINGP, "member_array" : C_MEMBER_ARRAY, "mkdir" : C_MKDIR, "mkmapping" : C_MKMAPPING, "move_object" : C_MOVE_OBJECT, "next_inventory" : C_NEXT_INVENTORY, "notify_fail" : C_NOTIFY_FAIL, "objectp" : C_OBJECTP, "parse_string" : C_PARSE_STRING, "pointerp" : C_POINTERP, "present" : C_PRESENT, "previous_object" : C_PREVIOUS_OBJECT, "query_host_name" : C_QUERY_HOST_NAME, "query_idle" : C_QUERY_IDLE, "query_ip_name" : C_QUERY_IP_NAME, "query_ip_number" : C_QUERY_IP_NUMBER, "query_load_average":C_QUERY_LOAD_AVERAGE, "query_snoop" : C_QUERY_SNOOP, "query_verb" : C_QUERY_VERB, "random" : C_RANDOM, "read_bytes" : C_READ_BYTES, "read_file" : C_READ_FILE, "remove_call_out" : C_REMOVE_CALL_OUT, "rename" : C_RENAME, "restore_object" : C_RESTORE_OBJECT, "rm" : C_RM, "rmdir" : C_RMDIR, "save_object" : C_SAVE_OBJECT, "say" : C_SAY, "set_bit" : C_SET_BIT, "set_heart_beat" : C_SET_HEART_BEAT, "set_living_name" : C_SET_LIVING_NAME, "set_this_player" : C_SET_THIS_PLAYER, "shout" : C_SHOUT, "shutdown" : C_SHUTDOWN, "sizeof" : C_SIZEOF, "snoop" : C_SNOOP, "sort_array" : C_SORT_ARRAY, "status" : C_STATUS, "stringp" : C_STRINGP, "strlen" : C_STRLEN, "swapout" : C_SWAPOUT, "tail" : C_TAIL, "tell_object" : C_TELL_OBJECT, "tell_room" : C_TELL_ROOM, "test_bit" : C_TEST_BIT, "this_object" : C_THIS_OBJECT, "this_player" : C_THIS_PLAYER, "time" : C_TIME, "transfer" : C_TRANSFER, "unique_array" : C_UNIQUE_ARRAY, "users" : C_USERS, "version" : C_VERSION, "wizlist" : C_WIZLIST, "write" : C_WRITE, "write_bytes" : C_WRITE_BYTES, "write_file" : C_WRITE_FILE, ]); minmax = ({ MINMAX(1, 255), /* IF */ MINMAX(1, 255), /* IFNOT */ MINMAX(2, 2), /* LAND */ MINMAX(2, 2), /* LOR */ MINMAX(3, 255), /* WHILE */ MINMAX(3, 255), /* DO */ MINMAX(2, 255), /* PROGN */ MINMAX(2, 254), /* ASSIGN */ MINMAX(2, 254), /* PLUSEQ */ MINMAX(2, 254), /* MINEQ */ MINMAX(2, 254), /* MULTEQ */ MINMAX(2, 254), /* DIVEQ */ MINMAX(2, 254), /* MODEQ */ MINMAX(2, 254), /* LSHIFTEQ */ MINMAX(2, 254), /* RSHIFTEQ */ MINMAX(2, 254), /* ANDEQ */ MINMAX(2, 254), /* XOREQ */ MINMAX(2, 254), /* OREQ */ MINMAX(1, 255), /* PLUSPLUS */ MINMAX(1, 255), /* MINMIN */ MINMAX(2, 255), /* SSCANF */ MINMAX(2, 2), /* INDEX */ MINMAX(3, 3), /* RANGE */ MINMAX(2, 255), /* CALL_OTHER */ MINMAX(1, 1), /* NOT */ MINMAX(1, 1), /* LNOT */ MINMAX(1, 1), /* NEGATE */ MINMAX(2, 2), /* MULT */ MINMAX(2, 2), /* DIV */ MINMAX(2, 2), /* MOD */ MINMAX(2, 2), /* PLUS */ MINMAX(2, 2), /* MIN */ MINMAX(2, 2), /* LSHIFT */ MINMAX(2, 2), /* RSHIFT */ MINMAX(2, 2), /* LESS */ MINMAX(2, 2), /* LESSEQ */ MINMAX(2, 2), /* GREATER */ MINMAX(2, 2), /* GREATEREQ */ MINMAX(2, 2), /* EQ */ MINMAX(2, 2), /* NOTEQ */ MINMAX(2, 2), /* AND */ MINMAX(2, 2), /* XOR */ MINMAX(2, 2), /* OR */ MINMAX(1, 1), /* QUOTE */ MINMAX(1, 3), /* ADD_ACTION */ MINMAX(1, 1), /* ADD_VERB */ MINMAX(1, 2), /* ADD_WORTH */ MINMAX(0, 1), /* ALL_INVENTORY */ MINMAX(1, 1), /* ALLOCATE */ MINMAX(1, 255), /* APPLY */ MINMAX(2, 255), /* CALL_OUT */ MINMAX(0, 0), /* CALL_TRACE */ MINMAX(1, 1), /* CAPITALIZE */ MINMAX(1, 3), /* CAT */ MINMAX(1, 1), /* CINDENT */ MINMAX(2, 2), /* CLEAR_BIT */ MINMAX(1, 1), /* CLONE_OBJECT */ MINMAX(1, 1), /* CLOSUREP */ MINMAX(1, 2), /* COMMAND */ MINMAX(1, 2), /* CREATE_WIZARD */ MINMAX(1, 1), /* CREATOR */ MINMAX(1, 2), /* CRYPT */ MINMAX(1, 1), /* CTIME */ MINMAX(1, 1), /* DEEP_INVENTORY */ MINMAX(1, 1), /* DESTRUCT */ MINMAX(0, 0), /* DISABLE_COMMANDS */ MINMAX(0, 0), /* ENABLE_COMMANDS */ MINMAX(0, 1), /* ENVIRONMENT */ MINMAX(1, 1), /* ERROR */ MINMAX(2, 2), /* EXEC */ MINMAX(2, 2), /* EXPLODE */ MINMAX(1, 1), /* FILE_NAME */ MINMAX(1, 1), /* FILE_SIZE */ MINMAX(3, 4), /* FILTER_ARRAY */ MINMAX(3, 4), /* FILTER_MAPPING */ MINMAX(1, 1), /* FIND_CALL_OUT */ MINMAX(1, 1), /* FIND_LIVING */ MINMAX(1, 1), /* FIND_OBJECT */ MINMAX(1, 1), /* FIND_PLAYER */ MINMAX(0, 1), /* FIRST_INVENTORY */ MINMAX(2, 2), /* FUNCTION_EXISTS */ MINMAX(1, 1), /* GET_DIR */ MINMAX(0, 0), /* GET_EXEC_COST */ MINMAX(2, 2), /* IMPLODE */ MINMAX(0, 1), /* INTERACTIVE */ MINMAX(1, 1), /* INTP */ MINMAX(1, 2), /* LAMBDA */ MINMAX(1, 1), /* LIVING */ MINMAX(0, 0), /* LOCALCMD */ MINMAX(2, 2), /* LOG_FILE */ MINMAX(1, 1), /* LOWER_CASE */ MINMAX(1, 1), /* LS */ MINMAX(2, 2), /* M_DELETE */ MINMAX(1, 1), /* M_INDICES */ MINMAX(1, 1), /* M_SIZEOF */ MINMAX(1, 1), /* M_VALUES */ MINMAX(3, 4), /* MAP_ARRAY */ MINMAX(3, 4), /* MAP_MAPPING */ MINMAX(1, 1), /* MAPPINGP */ MINMAX(2, 2), /* MEMBER_ARRAY */ MINMAX(1, 1), /* MKDIR */ MINMAX(2, 2), /* MKMAPPING */ MINMAX(2, 2), /* MOVE_OBJECT */ MINMAX(0, 1), /* NEXT_INVENTORY */ MINMAX(1, 1), /* NOTIFY_FAIL */ MINMAX(1, 1), /* OBJECTP */ MINMAX(2, 2), /* PARSE_STRING */ MINMAX(1, 1), /* POINTERP */ MINMAX(1, 2), /* PRESENT */ MINMAX(0, 0), /* PREVIOUS_OBJECT */ MINMAX(0, 0), /* QUERY_HOST_NAME */ MINMAX(1, 1), /* QUERY_IDLE */ MINMAX(0, 1), /* QUERY_IP_NAME */ MINMAX(0, 1), /* QUERY_IP_NUMBER */ MINMAX(0, 0), /* QUERY_LOAD_AVERAGE */ MINMAX(1, 1), /* QUERY_SNOOP */ MINMAX(0, 0), /* QUERY_VERB */ MINMAX(1, 1), /* RANDOM */ MINMAX(1, 3), /* READ_BYTES */ MINMAX(1, 3), /* READ_FILE */ MINMAX(1, 1), /* REMOVE_CALL_OUT */ MINMAX(2, 2), /* RENAME */ MINMAX(1, 1), /* RESTORE_OBJECT */ MINMAX(1, 1), /* RM */ MINMAX(1, 1), /* RMDIR */ MINMAX(1, 1), /* SAVE_OBJECT */ MINMAX(1, 2), /* SAY */ MINMAX(2, 2), /* SET_BIT */ MINMAX(1, 1), /* SET_HEART_BEAT */ MINMAX(1, 1), /* SET_LIVING_NAME */ MINMAX(1, 1), /* SET_THIS_PLAYER */ MINMAX(1, 1), /* SHOUT */ MINMAX(0, 0), /* SHUTDOWN */ MINMAX(1, 1), /* SIZEOF */ MINMAX(1, 1), /* SNOOP */ MINMAX(2, 3), /* SORT_ARRAY */ MINMAX(0, 1), /* STATUS */ MINMAX(1, 1), /* STRINGP */ MINMAX(1, 1), /* STRLEN */ MINMAX(0, 1), /* SWAPOUT */ MINMAX(1, 1), /* TAIL */ MINMAX(2, 2), /* TELL_OBJECT */ MINMAX(2, 3), /* TELL_ROOM */ MINMAX(2, 2), /* TEST_BIT */ MINMAX(0, 0), /* THIS_OBJECT */ MINMAX(0, 1), /* THIS_PLAYER */ MINMAX(0, 0), /* TIME */ MINMAX(2, 2), /* TRANSFER */ MINMAX(2, 3), /* UNIQUE_ARRAY */ MINMAX(0, 0), /* USERS */ MINMAX(0, 0), /* VERSION */ MINMAX(0, 1), /* WIZLIST */ MINMAX(1, 1), /* WRITE */ MINMAX(3, 3), /* WRITE_BYTES */ MINMAX(2, 2), /* WRITE_FILE */ }); } } /* * NAME: set_this_player() * DESCRIPTION: set the current player */ void set_this_player(object player) { command_giver = player; } /* * NAME: query_this_player() * DESCRIPTION: return the current player, or interactive user */ object query_this_player() { return command_giver; } /* * NAME: set_verb() * DESCRIPTION: set the current verb */ void set_verb(string str) { if (PRIVILEGED()) { verb = str; } } /* * NAME: query_verb() * DESCRIPTION: return the current verb */ string query_verb() { return verb; } /* * NAME: set_living_name() * DESCRIPTION: set the living name of the current object */ void set_living_name(string name) { object obj, *list; if (PRIVILEGED()) { obj = previous_object(); if (living(obj)) { if (interactive(obj) != 0) { players[name] = obj; } else { list = monsters[name]; if (list == 0) { list = ({ obj }); } else { list = ({ obj }) + (list - ({ 0 })); } monsters[name] = list; } } } } /* * NAME: query_find_player() * DESCRIPTION: find a player by name */ object query_find_player(string name) { object obj; obj = players[name]; if (obj != 0 && living(obj)) { return obj; } return 0; } /* * NAME: query_find_living() * DESCRIPTION: find a living object by name */ object query_find_living(string name) { object obj, *list; int i, sz; obj = query_find_player(name); if (obj != 0) { return obj; } list = monsters[name]; if (list != 0 && sizeof(list) != 0) { list -= ({ 0 }); monsters[name] = list; for (i = 0, sz = sizeof(list); i < sz; i++) { if (living(obj=list[i])) { return obj; } } } return 0; } /* * NAME: add_object() * DESCRIPTION: add an object */ void add_object() { if (PRIVILEGED()) { if (objects == 0) { objects = ([ ]); } objects[creator(previous_object())]++; } } /* * NAME: del_object() * DESCRIPTION: delete an object */ void del_object() { if (PRIVILEGED()) { objects[creator(previous_object())]--; } } /* * NAME: add_call_out() * DESCRIPTION: add a call_out */ void add_call_out(int delay) { if (PRIVILEGED()) { string creator; call_outs[creator = creator(previous_object())]++; call_out("fix_player", delay, creator, command_giver); } } /* * NAME: fix_player() * DESCRIPTION: set this_player() in preparation of the next call_out */ static void fix_player(string creator, object player) { call_outs[creator]--; command_giver = player; } /* * NAME: add_heart_beat() * DESCRIPTION: add a heart_beat */ void add_heart_beat() { if (PRIVILEGED()) { heart_beats[creator(previous_object())]++; } } /* * NAME: del_heart_beat() * DESCRIPTION: delete a heart_beat */ void del_heart_beat() { if (PRIVILEGED()) { heart_beats[creator(previous_object())]--; } } /* * NAME: show_wiz_list() * DESCRIPTION: show the wizlist */ void show_wiz_list() { string *wizards, name; int i, sz; write("name\t objects hbeats callouts\n" + "-------------------------------------\n"); wizards = map_indices(objects); for (i = 0, sz = sizeof(wizards); i < sz; i++) { if (wizards[i] == 0) { name = "Mudlib"; } else { name = wizards[i]; } if (strlen(name) < 8) { name += "\t"; } write(name + "\t" + objects[wizards[i]] + "\t" + heart_beats[wizards[i]] + "\t" + call_outs[wizards[i]] + "\n"); } } /* * NAME: ident() * DESCRIPTION: return 1 if the argument is an identifier, 0 otherwise */ private int ident(mixed arg) { int i, len, c; if (!stringp(arg)) { return 0; } len = strlen(arg); if (len == 0) { return 0; } c = arg[0]; if ((c < 'a' || c > 'z') && (c < 'A' || c > 'Z') && c != '_') { return 0; } for (i = 1; i < len; i++) { c = arg[i]; if ((c < 'a' || c > 'z') && (c < 'A' || c > 'Z') && c != '_' && (c < '0' || c > '9')) { return 0; } } return 1; } /* * NAME: eval() * DESCRIPTION: evaluate an expression */ mapping eval(mixed expr, mapping vars) { mixed code, *args, cond, body; int nargs, i; mapping old; if (stringp(expr)) { /* possibly a variable */ vars[1] = (strlen(expr) > 1 && expr[0] == '\'') ? vars[expr] : expr; return vars; } else if (!arrayp(expr) || sizeof(expr) == 0 || !closurep(expr[0])) { /* ordinary expression */ vars[1] = expr; return vars; } /* closure */ args = expr[1 ..]; expr = expr[0]; code = expr[1]; if (sizeof(expr) == 2) { /* * short format */ if ((nargs=sizeof(args)) < MIN(code)) { error("Too few arguments for closure"); } else if (nargs > MAX(code)) { error("Too many arguments for closure"); } } else { /* * long format */ nargs = expr[2]; if (nargs != sizeof(args)) { if (nargs < sizeof(args)) { error("Too many arguments for closure"); } else { error("Too few arguments for closure"); } } /* bind parameters */ body = ([ ]); for (i = 0; i < nargs; i++) { body[expr[i + 3]] = (vars=eval(args[i], vars))[1]; } old = vars & expr[3 .. nargs + 2]; /* old parameter values */ vars += body; /* use new parameter values */ args = expr[nargs + 3 ..]; /* closure arguments */ expr = expr[3 .. nargs + 2]; /* parameter names */ nargs = sizeof(args); /* deal with special codes */ switch (code) { case C_IF: for (i = 1; i < nargs; i += 2) { if ((vars=eval(args[i - 1], vars))[1]) { return (eval(args[i], vars) - expr) + old; } } return (eval(args[i - 1], vars) - expr) + old; case C_IFNOT: for (i = 1; i < nargs; i += 2) { if (!(vars=eval(args[i - 1], vars))[1]) { return (eval(args[i], vars) - expr) + old; } } return (eval(args[i - 1], vars) - expr) + old; case C_LAND: if (!(vars=eval(args[0], vars))[1]) { vars[1] = 0; return (vars - expr) + old; } vars = eval(args[1], vars); vars[1] = !!vars[1]; return (vars - expr) + old; case C_LOR: if ((vars=eval(args[0], vars))[1]) { vars[1] = 1; return (vars - expr) + old; } vars = eval(args[1], vars); vars[1] = !!vars[1]; return (vars - expr) + old; case C_WHILE: cond = args[0]; body = args[2]; while ((vars=eval(cond, vars))[1]) { vars = eval(body, vars); } return (eval(args[1], vars) - expr) + old; case C_DO: body = args[0]; cond = args[1]; do { vars = eval(body, vars); } while ((vars=eval(cond, vars))[1]); return (eval(args[2], vars) - expr) + old; case C_ASSIGN: for (i = 0; i < nargs; i += 2) { vars = eval(args[i + 1], vars); vars[args[i]] = vars[1]; } return (vars - expr) + old; case C_PLUSEQ: for (i = 0; i < nargs; i += 2) { vars = eval(args[i + 1], vars); vars[args[i]] += vars[1]; } vars[1] = vars[args[i - 2]]; return (vars - expr) + old; case C_MINEQ: for (i = 0; i < nargs; i += 2) { vars = eval(args[i + 1], vars); vars[args[i]] -= vars[1]; } vars[1] = vars[args[i - 2]]; return (vars - expr) + old; case C_MULTEQ: for (i = 0; i < nargs; i += 2) { vars = eval(args[i + 1], vars); vars[args[i]] *= vars[1]; } vars[1] = vars[args[i - 2]]; return (vars - expr) + old; case C_DIVEQ: for (i = 0; i < nargs; i += 2) { vars = eval(args[i + 1], vars); vars[args[i]] /= vars[1]; } vars[1] = vars[args[i - 2]]; return (vars - expr) + old; case C_MODEQ: for (i = 0; i < nargs; i += 2) { vars = eval(args[i + 1], vars); vars[args[i]] %= vars[1]; } vars[1] = vars[args[i - 2]]; return (vars - expr) + old; case C_LSHIFTEQ: for (i = 0; i < nargs; i += 2) { vars = eval(args[i + 1], vars); vars[args[i]] <<= vars[1]; } vars[1] = vars[args[i - 2]]; return (vars - expr) + old; case C_RSHIFTEQ: for (i = 0; i < nargs; i += 2) { vars = eval(args[i + 1], vars); vars[args[i]] >>= vars[1]; } vars[1] = vars[args[i - 2]]; return (vars - expr) + old; case C_ANDEQ: for (i = 0; i < nargs; i += 2) { vars = eval(args[i + 1], vars); vars[args[i]] &= vars[1]; } vars[1] = vars[args[i - 2]]; return (vars - expr) + old; case C_XOREQ: for (i = 0; i < nargs; i += 2) { vars = eval(args[i + 1], vars); vars[args[i]] ^= vars[1]; } vars[1] = vars[args[i - 2]]; return (vars - expr) + old; case C_OREQ: for (i = 0; i < nargs; i += 2) { vars = eval(args[i + 1], vars); vars[args[i]] |= vars[1]; } vars[1] = vars[args[i - 2]]; return (vars - expr) + old; case C_PLUSPLUS: for (i = nargs; i > 0; ) { vars[args[--i]]++; } vars[1] = vars[args[nargs - 1]]; return (vars - expr) + old; case C_MINMIN: for (i = nargs; i > 0; ) { --vars[args[--i]]; } vars[1] = vars[args[nargs - 1]]; return (vars - expr) + old; case C_SSCANF: args[0] = (vars=eval(args[0], vars))[1]; args[1] = (vars=eval(args[1], vars))[1]; body = args[2 ..]; for (i = vars[1] = sscanf(args...); i > 0; ) { --i; vars[body[i]] = args[i + 2]; } return (vars - expr) + old; } /* * not a special code: evaluate all arguments */ for (i = 0; i < nargs; i++) { args[i] = (vars=eval(args[i], vars))[1]; } vars = (vars - expr) + old; /* remove parameters, add old values */ } if (stringp(code)) { /* local function */ vars[1] = call_other(previous_object(), code, args...); return vars; } vars[1] = 0; switch (code) { case C_PROGN: vars[1] = args[nargs - 1]; break; case C_INDEX: vars[1] = args[0][args[1]]; break; case C_RANGE: vars[1] = args[0][args[1] .. args[2]]; break; case C_CALL_OTHER: vars[1] = call_other(args...); break; case C_NOT: vars[1] = ~args[0]; break; case C_LNOT: vars[1] = !args[0]; break; case C_NEGATE: vars[1] = -args[0]; break; case C_MULT: vars[1] = args[0] * args[1]; break; case C_DIV: vars[1] = args[0] / args[1]; break; case C_MOD: vars[1] = args[0] % args[1]; break; case C_PLUS: vars[1] = args[0] + args[1]; break; case C_MIN: vars[1] = args[0] - args[1]; break; case C_LSHIFT: vars[1] = args[0] << args[1]; break; case C_RSHIFT: vars[1] = args[0] >> args[1]; break; case C_LESS: vars[1] = args[0] < args[1]; break; case C_LESSEQ: vars[1] = args[0] <= args[1]; break; case C_GREATER: vars[1] = args[0] > args[1]; break; case C_GREATEREQ: vars[1] = args[0] >= args[1]; break; case C_EQ: vars[1] = args[0] == args[1]; break; case C_NOTEQ: vars[1] = args[0] != args[1]; break; case C_AND: vars[1] = args[0] & args[1]; break; case C_XOR: vars[1] = args[0] ^ args[1]; break; case C_OR: vars[1] = args[0] | args[1]; break; case C_QUOTE: vars[1] = args[0]; break; case C_ADD_ACTION: add_action(args...); break; case C_ADD_VERB: add_verb(args[0]); break; case C_ADD_WORTH: if (nargs == 1) { add_worth(args[0], previous_object(1)); } else { add_worth(args[0], args[1]); } break; case C_ALL_INVENTORY: if (nargs == 0) { vars[1] = all_inventory(previous_object()); } else { vars[1] = all_inventory(args[0]); } break; case C_ALLOCATE: vars[1] = allocate(args[0]); break; case C_APPLY: vars[1] = eval(args, vars); break; case C_CALL_OUT: call_out(args...); break; case C_CALL_TRACE: vars[1] = call_trace(); break; case C_CAPITALIZE: vars[1] = capitalize(args[0]); break; case C_CAT: vars[1] = cat(args...); break; case C_CINDENT: vars[1] = cindent(args[0]); break; case C_CLEAR_BIT: vars[1] = clear_bit(args[0], args[1]); break; case C_CLONE_OBJECT: vars[1] = clone_object(args[0]); break; case C_CLOSUREP: vars[1] = closurep(args[0]); break; case C_COMMAND: if (nargs == 1) { vars[1] = command(args[0], previous_object()); } else { vars[1] = command(args[0], args[1]); } break; case C_CREATE_WIZARD: vars[1] = create_wizard(args...); break; case C_CREATOR: vars[1] = creator(args[0]); break; case C_CRYPT: vars[1] = crypt(args...); break; case C_CTIME: vars[1] = ctime(args[0]); break; case C_DEEP_INVENTORY: vars[1] = deep_inventory(args[0]); break; case C_DESTRUCT: destruct(args[0]); break; case C_DISABLE_COMMANDS: disable_commands(); break; case C_ENABLE_COMMANDS: enable_commands(); break; case C_ENVIRONMENT: if (nargs == 0) { vars[1] = environment(previous_object()); } else { vars[1] = environment(args[0]); } break; case C_ERROR: error(args[0]); case C_EXEC: vars[1] = exec(args[0], args[1]); break; case C_EXPLODE: vars[1] = explode(args[0], args[1]); break; case C_FILE_NAME: vars[1] = file_name(args[0]); break; case C_FILE_SIZE: vars[1] = file_size(args[0]); break; case C_FILTER_ARRAY: vars[1] = filter_array(args...); break; case C_FILTER_MAPPING: vars[1] = filter_mapping(args...); break; case C_FIND_CALL_OUT: vars[1] = find_call_out(args[0]); break; case C_FIND_LIVING: vars[1] = find_living(args[0]); break; case C_FIND_OBJECT: vars[1] = find_object(args[0]); break; case C_FIND_PLAYER: vars[1] = find_player(args[0]); break; case C_FIRST_INVENTORY: if (nargs == 0) { vars[1] = first_inventory(previous_object()); } else { vars[1] = first_inventory(args[0]); } break; case C_FUNCTION_EXISTS: vars[1] = function_exists(args[0], args[1]); break; case C_GET_DIR: vars[1] = get_dir(args[0]); break; case C_GET_EXEC_COST: vars[1] = get_exec_cost(); break; case C_IMPLODE: vars[1] = implode(args[0], args[1]); break; case C_INTERACTIVE: if (nargs == 0) { vars[1] = interactive(previous_object()); } else { vars[1] = interactive(args[0]); } break; case C_INTP: vars[1] = intp(args[0]); break; case C_LAMBDA: vars[1] = lambda(args...); break; case C_LIVING: vars[1] = living(args[0]); break; case C_LOCALCMD: localcmd(); break; case C_LOG_FILE: log_file(args[0], args[1]); break; case C_LOWER_CASE: vars[1] = lower_case(args[0]); break; case C_LS: vars[1] = ls(args[0]); break; case C_M_DELETE: vars[1] = m_delete(args[0], args[1]); break; case C_M_INDICES: vars[1] = m_indices(args[0]); break; case C_M_SIZEOF: vars[1] = m_sizeof(args[0]); break; case C_M_VALUES: vars[1] = m_values(args[0]); break; case C_MAP_ARRAY: vars[1] = map_array(args...); break; case C_MAP_MAPPING: vars[1] = map_mapping(args...); break; case C_MAPPINGP: vars[1] = mappingp(args[0]); break; case C_MEMBER_ARRAY: vars[1] = member_array(args[0], args[1]); break; case C_MKDIR: vars[1] = mkdir(args[0]); break; case C_MKMAPPING: vars[1] = mkmapping(args[0], args[1]); break; case C_MOVE_OBJECT: move_object(args[0], args[1]); break; case C_NEXT_INVENTORY: if (nargs == 0) { vars[1] = next_inventory(previous_object()); } else { vars[1] = next_inventory(args[0]); } break; case C_NOTIFY_FAIL: notify_fail(args[0]); break; case C_OBJECTP: vars[1] = objectp(args[0]); break; case C_PARSE_STRING: vars[1] = parse_string(args[0], args[1]); break; case C_POINTERP: vars[1] = pointerp(args[0]); break; case C_PRESENT: if (nargs == 1) { vars[1] = present(args[0], previous_object()); } else { vars[1] = present(args[0], args[1]); } break; case C_PREVIOUS_OBJECT: vars[1] = previous_object(1); break; case C_QUERY_HOST_NAME: vars[1] = query_host_name(); break; case C_QUERY_IDLE: vars[1] = query_idle(args[0]); break; case C_QUERY_IP_NAME: vars[1] = query_ip_name(args...); break; case C_QUERY_IP_NUMBER: vars[1] = query_ip_number(args...); break; case C_QUERY_LOAD_AVERAGE: vars[1] = query_load_average(); break; case C_QUERY_SNOOP: vars[1] = query_snoop(args[0]); break; case C_QUERY_VERB: vars[1] = query_verb(); break; case C_RANDOM: vars[1] = random(args[0]); break; case C_READ_BYTES: vars[1] = read_bytes(args...); break; case C_READ_FILE: vars[1] = read_file(args...); break; case C_REMOVE_CALL_OUT: vars[1] = remove_call_out(args[0]); break; case C_RENAME: vars[1] = rename(args[0], args[1]); break; case C_RESTORE_OBJECT: vars[1] = restore_object(args[0]); break; case C_RM: vars[1] = rm(args[0]); break; case C_RMDIR: vars[1] = rmdir(args[0]); break; case C_SAVE_OBJECT: save_object(args[0]); break; case C_SAY: say(args...); break; case C_SET_BIT: vars[1] = set_bit(args[0], args[1]); break; case C_SET_HEART_BEAT: vars[1] = set_heart_beat(args[0]); break; case C_SET_LIVING_NAME: set_living_name(args[0]); break; case C_SET_THIS_PLAYER: set_this_player(args[0]); break; case C_SHOUT: shout(args[0]); break; case C_SHUTDOWN: shutdown(); break; case C_SIZEOF: vars[1] = sizeof(args[0]); break; case C_SNOOP: vars[1] = snoop(args[0]); break; case C_SORT_ARRAY: if (nargs == 2 && stringp(args[1])) { vars[1] = sort_array(args[0], args[1], previous_object()); } else { vars[1] = sort_array(args...); } break; case C_STATUS: vars[1] = status(args...); break; case C_STRINGP: vars[1] = stringp(args[0]); break; case C_STRLEN: vars[1] = strlen(args[0]); break; case C_SWAPOUT: swapout(args...); break; case C_TAIL: vars[1] = tail(args[0]); break; case C_TELL_OBJECT: tell_object(args[0], args[1]); break; case C_TELL_ROOM: tell_room(args...); break; case C_TEST_BIT: vars[1] = test_bit(args[0], args[1]); break; case C_THIS_OBJECT: vars[1] = previous_object(); break; case C_THIS_PLAYER: vars[1] = this_player(args...); break; case C_TIME: vars[1] = time(); break; case C_TRANSFER: vars[1] = transfer(args[0], args[1]); break; case C_UNIQUE_ARRAY: vars[1] = unique_array(args...); break; case C_USERS: vars[1] = users(); break; case C_VERSION: vars[1] = version(); break; case C_WIZLIST: wizlist(args...); break; case C_WRITE: write(args[0]); break; case C_WRITE_BYTES: vars[1] = write_bytes(args[0], args[1], args[2]); break; case C_WRITE_FILE: vars[1] = write_file(args[0], args[1]); break; default: error("Unknown closure"); } return vars; } /* * NAME: compile() * DESCRIPTION: compile a lambda expression to a closure */ closure compile(mixed func, mixed *def) { int code, i, j, nargs; mixed arg; if (def == 0) { /* * short format */ code = codes[func]; if (code != 0) { if (code <= C_CONTROL) { error("Lambda: short format only for efuns, operators and " + "local functions"); } func = code; } else if (!ident(func)) { error("Lambda: bad function"); } return ({ LAMBDA, code }); } else { /* * long format */ for (i = 0, nargs = sizeof(func); i < nargs; i++) { arg = func[i]; if (!stringp(arg) || strlen(arg) <= 1 || !ident(arg[1 ..])) { error("Lambda: invalid parameter " + (i + 1)); } for (j = 0; j < i; j++) { if (func[j] == func[i]) { error("Lambda: duplicate parameter"); } } } code = codes[def[0]]; if (code != 0) { i = sizeof(def) - 1; if (i < MIN(code)) { error("Lambda: too few arguments"); } else if (i > MAX(code)) { error("Lambda: too many arguments"); } else { switch (code) { case C_IF: case C_IFNOT: if ((i & 1) == 0) { error("Lambda: odd number of arguments required"); } break; case C_ASSIGN: case C_PLUSEQ: case C_MINEQ: case C_MULTEQ: case C_DIVEQ: case C_MODEQ: case C_LSHIFTEQ: case C_RSHIFTEQ: case C_ANDEQ: case C_XOREQ: case C_OREQ: if ((i & 1) != 0) { error("Lambda: even number of arguments required"); } for (j = 1; j <= i; j += 2) { arg = def[j]; if (!stringp(arg) || strlen(arg) <= 1 || !ident(arg[1 ..])) { error("Lambda: invalid argument " + j); } } break; case C_PLUSPLUS: case C_MINMIN: for (j = 1; j <= i; j++) { arg = def[j]; if (!stringp(arg) || strlen(arg) <= 1 || !ident(arg[1 ..])) { error("Lambda: invalid argument " + j); } } break; case C_SSCANF: for (j = 3; j <= i; j++) { arg = def[j]; if (!stringp(arg) || strlen(arg) <= 1 || !ident(arg[1 ..])) { error("Lambda: invalid argument " + j); } } break; } } arg = code; } else if (!ident(arg=def[0])) { error("Lambda: bad function"); } return ({ LAMBDA, code, nargs }) + func + def[1 ..]; } } /* * NAME: filter_array * DESCRIPTION: filter the elements of an array */ varargs mixed *lambda_filter_array(mixed *arr, closure func) { mixed *copy, elt; int i, j, sz; copy = allocate(sz = sizeof(arr)); for (i = 0, j = -1; i < sz; i++) { if (eval(({ func, elt = arr[i] }), ([ ]))[1]) { copy[++j] = elt; } } return copy[0 .. j]; } /* * NAME: map_array * DESCRIPTION: map the elements of an array */ varargs mixed *lambda_map_array(mixed *arr, closure func) { mixed *copy; int i, sz; copy = allocate(sz = sizeof(arr)); for (i = 0; i < sz; i++) { copy[i] = eval(({ func, arr[i] }), ([ ])[1]); } return copy; } /* * NAME: sort_array() * DESCRIPTION: sort an array */ varargs mixed *lambda_sort_array(mixed *arr, closure func) { mixed elt, val; int n, i, j, size; arr = arr[..]; for (n = 1, size = sizeof(arr); n < size; n <<= 1) ; for (n >>= 1; n > 0; --n) { elt = arr[n - 1]; for (i = n, j = n << 1; j <= size; i = j, j <<= 1) { val = arr[j - 1]; if (j < size && eval(({ func, arr[j], val }), ([ ]))[1]) { val = arr[j++]; } if (eval(({ func, elt, val }), ([ ]))[1]) { break; } arr[i - 1] = val; } arr[i - 1] = elt; } for (n = size - 1; n > 0; --n) { elt = arr[n]; arr[n] = arr[0]; for (i = 1, j = 2; j <= n; i = j, j <<= 1) { val = arr[j - 1]; if (j < n && eval(({ func, arr[j], val }), ([ ]))[1]) { val = arr[j++]; } if (eval(({ func, elt, val }), ([ ]))[1]) { break; } arr[i - 1] = val; } arr[i - 1] = elt; } return arr; } /* * NAME: filter_mapping() * DESCRIPTION: filter a mapping by its values */ varargs mapping lambda_filter_mapping(mapping map, closure func) { mixed *indices, *values, value; mapping copy; int i, sz; indices = map_indices(map); values = map_values(map); copy = ([ ]); for (i = 0, sz = sizeof(indices); i < sz; i++) { if (eval(({ func, value = values[i] }), ([ ]))[1]) { copy[indices[i]] = value; } } return copy; } /* * NAME: map_mapping() * DESCRIPTION: map the values of a mapping */ varargs mapping lambda_map_mapping(mapping map, closure func) { mixed *indices, *values; mapping copy; int i, sz; indices = map_indices(map); values = map_values(map); copy = ([ ]); for (i = 0, sz = sizeof(indices); i < sz; i++) { copy[indices[i]] = eval(({ func, values[i] }), ([ ])[1]); } return copy; }