From: Rick L Bird Date: Sat, 23 Apr 2011 05:18:37 +0000 (-0400) Subject: PennMUSH Enhancements 1.8.3p10 X-Git-Url: https://git.theari.com/?a=commitdiff_plain;h=04740e9eef9572dec36203a270ad526a06321d76;p=cobramush.git PennMUSH Enhancements 1.8.3p10 Commit Refs: #97 to #123 --- diff --git a/configure.ac b/configure.ac index 455906c..6a3ae14 100644 --- a/configure.ac +++ b/configure.ac @@ -205,7 +205,13 @@ AC_CHECK_LIB(intl, gettext) AC_CHECK_LIB(crypt, crypt) LIB_SOCKET_NSL AC_CHECK_LIB(fam, FAMOpen) -AC_CHECK_LIB(z, gzungetc) + + +AC_ARG_ENABLE(zlib, AS_HELP_STRING([--disable-zlib], [Don't use zlib for database compression.]), + enable_zlib=$enableval, enable_zlib=yes) +if test "$enable_zlib" = "yes"; then + AC_CHECK_LIB(z, gzungetc) +fi # with_ssl=set CHECK_SSL diff --git a/hdrs/SFMT.h b/hdrs/SFMT.h index 8729b62..4e78ce3 100644 --- a/hdrs/SFMT.h +++ b/hdrs/SFMT.h @@ -36,8 +36,6 @@ #if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) #include #elif defined(_MSC_VER) || defined(__BORLANDC__) -typedef unsigned int uint32_t; -typedef unsigned __int64 uint64_t; #define inline __inline #else #include diff --git a/hdrs/lock.h b/hdrs/lock.h index af1c671..9e3f313 100644 --- a/hdrs/lock.h +++ b/hdrs/lock.h @@ -76,6 +76,9 @@ void do_list_locks(dbref player, const char *arg, int lc, const char *label); void list_locks(char *buff, char **bp, const char *name); const char *lock_flags(lock_list *ll); const char *lock_flags_long(lock_list *ll); +void list_lock_flags(char *buff, char **bp); +void list_lock_flags_long(char *buff, char **bp); +lock_list *getlockstruct(dbref thing, lock_type type); void check_zone_lock(dbref player, dbref zone, int noisy); void define_lock(lock_type name, privbits flags); #define L_FLAGS(lock) ((lock)->flags) diff --git a/hdrs/mushdb.h b/hdrs/mushdb.h index 56ac553..227bea4 100644 --- a/hdrs/mushdb.h +++ b/hdrs/mushdb.h @@ -222,7 +222,7 @@ bool unfindable(dbref); #define DBF_DIVISIONS 0x40000 #define DBF_LABELS 0x100000 #define DBF_SPIFFY_AF_ANSI 0x200000 - +#define DBF_HEAR_CONNECT 0x400000 /* CobraMUSH Specific DBF Flags */ #define DBF_NEW_ATR_LOCK 0x200000 diff --git a/hdrs/parse.h b/hdrs/parse.h index 6dd83bd..4eb7715 100644 --- a/hdrs/parse.h +++ b/hdrs/parse.h @@ -79,6 +79,7 @@ bool is_objid(char const *str); bool is_integer(char const *str); bool is_uinteger(char const *str); +bool is_strict_uinteger(const char *str); bool is_boolean(char const *str); /* Split a sep-delimited string into individual elements */ diff --git a/src/atr_tab.c b/src/atr_tab.c index 0330726..d893f97 100644 --- a/src/atr_tab.c +++ b/src/atr_tab.c @@ -534,6 +534,7 @@ list_attribs(void) int nptrs = 0, i; ap = (ATTR *) ptab_firstentry(&ptab_attrib); + ptrs[0] = ""; while (ap) { ptrs[nptrs++] = AL_NAME(ap); ap = (ATTR *) ptab_nextentry(&ptab_attrib); diff --git a/src/attrib.c b/src/attrib.c index b459356..aa9375a 100644 --- a/src/attrib.c +++ b/src/attrib.c @@ -1258,7 +1258,8 @@ atr_comm_match(dbref thing, dbref player, int type, int end, parent_depth = GoodObject(Parent(thing)); } else { flag_mask = AF_LISTEN; - if (ThingInhearit(thing) || RoomInhearit(thing)) { + if (has_flag_by_name + (thing, "LISTEN_PARENT", TYPE_PLAYER | TYPE_THING | TYPE_ROOM)) { parent_depth = GoodObject(Parent(thing)); } else { parent_depth = 0; diff --git a/src/bsd.c b/src/bsd.c index a2bb918..a12a2b1 100644 --- a/src/bsd.c +++ b/src/bsd.c @@ -782,9 +782,8 @@ main(int argc, char **argv) shutdown_checkpoint(); #endif WSACleanup(); /* clean up */ -#else - exit(0); #endif + exit(0); } #endif /* BOOLEXP_DEBUGGING */ @@ -3952,6 +3951,32 @@ FUNCTION(fun_lwho) } } +#ifdef WIN32 +#pragma warning( disable : 4761) /* Disable bogus conversion warning */ +#endif +/* ARGSUSED */ +FUNCTION(fun_hidden) +{ + dbref it = match_thing(executor, args[0]); + if (CanSee(executor, it) && ((Admin(executor) || + Location(executor) == Location(it) || Location(it) == executor))) { + if ((it == NOTHING) || (!IsPlayer(it))) { + notify(executor, T("Couldn't find that player.")); + safe_str("#-1", buff, bp); + return; + } + safe_boolean(hidden(it), buff, bp); + return; + } else { + notify(executor, T("Permission denied.")); + safe_str("#-1", buff, bp); + return; + } +} + +#ifdef WIN32 +#pragma warning( default : 4761) /* Re-enable conversion warning */ +#endif /** Look up a DESC by character name or file descriptor. * \param executor the dbref of the object calling the function calling this. diff --git a/src/cmds.c b/src/cmds.c index c667661..5488185 100644 --- a/src/cmds.c +++ b/src/cmds.c @@ -76,7 +76,9 @@ COMMAND (cmd_atrlock) { } COMMAND (cmd_attribute) { - if (SW_ISSET(sw, SWITCH_ACCESS)) + if(SW_ISSET(sw, SWITCH_INFO) || !has_power(player, "GFUNCS")) { + do_attribute_info(player, arg_left); + } else if (SW_ISSET(sw, SWITCH_ACCESS)) do_attribute_access(player, arg_left, arg_right, SW_ISSET(sw, SWITCH_RETROACTIVE)); else if(SW_ISSET(sw, SWITCH_LOCK)) { @@ -87,10 +89,9 @@ COMMAND (cmd_attribute) { } else if (SW_ISSET(sw, SWITCH_DELETE)) do_attribute_delete(player, arg_left, SW_ISSET(sw, SWITCH_DEFAULTS)); - else if (SW_ISSET(sw, SWITCH_RENAME)) - do_attribute_rename(player, arg_left, arg_right); - else - do_attribute_info(player, arg_left); + else if (SW_ISSET(sw, SWITCH_RENAME)) { + do_attribute_rename(player, arg_left, arg_right); + } else notify(player, "You lost me..."); } COMMAND(cmd_atrchown) @@ -195,11 +196,11 @@ COMMAND(cmd_config) { int source = SW_ISSET(sw, SWITCH_SAVE) ? 2 : 1; if (source == 2) { - if (!God(player)) { - /* Only god can alter the original config file. */ - notify(player, T("You can't remake the world in your image.")); - return; - } + if (!God(player)) { + /* Only god can alter the original config file. */ + notify(player, T("You can't remake the world in your image.")); + return; + } } if (!config_set(arg_left, arg_right, source, 0) && !config_set(arg_left, arg_right, source, 1)) diff --git a/src/command.c b/src/command.c index 30b0f4f..a6b1716 100644 --- a/src/command.c +++ b/src/command.c @@ -87,7 +87,7 @@ COMLIST commands[] = { {"@ATRLOCK", "READ WRITE", cmd_atrlock, CMD_T_ANY | CMD_T_EQSPLIT, NULL}, {"@ATRCHOWN", NULL, cmd_atrchown, CMD_T_EQSPLIT, NULL}, {"@ATTRIBUTE", "ACCESS DEFAULTS LOCK WRITE READ DELETE RENAME RETROACTIVE", cmd_attribute, - CMD_T_ANY | CMD_T_EQSPLIT, "POWER^GFUNCS"}, + CMD_T_ANY | CMD_T_EQSPLIT, NULL}, {"@BOOT", "PORT ME", cmd_boot, CMD_T_ANY, NULL}, {"@BREAK", NULL, cmd_break, CMD_T_ANY | CMD_T_EQSPLIT | CMD_T_RS_NOPARSE, NULL}, #ifdef CHAT_SYSTEM @@ -1040,7 +1040,8 @@ command_parse(dbref player, dbref cause, dbref realcause, char *string, int from noevtoken = 1; p = string + 1; string = p; - memmove(global_eval_context.ccom, (char *) global_eval_context.ccom + 1, BUFFER_LEN - 1); + memmove(global_eval_context.ccom, (char *) global_eval_context.ccom + 1, + BUFFER_LEN - 1); } if (*p == '[') { if ((cmd = command_find("WARN_ON_MISSING"))) { @@ -1201,7 +1202,7 @@ command_parse(dbref player, dbref cause, dbref realcause, char *string, int from command_parse_free_args; return commandraw; } - + /* Parse out any switches */ sw = SW_ALLOC(); swp = switches; @@ -1290,54 +1291,56 @@ command_parse(dbref player, dbref cause, dbref realcause, char *string, int from } - /* Finish setting up commandraw, if we may need it for hooks */ - if (has_hook(&cmd->hooks.ignore) || has_hook(&cmd->hooks.override)) { - p = command2; - if (*p && (*p == ' ')) { - safe_chr(' ', commandraw, &c2); - p++; - } - if (cmd->type & CMD_T_ARGS) { - int lsa_index; - if (lsa[1]) { - safe_str(lsa[1], commandraw, &c2); - for (lsa_index = 2; lsa[lsa_index]; lsa_index++) { - safe_chr(',', commandraw, &c2); - safe_str(lsa[lsa_index], commandraw, &c2); - } - } - } else { - safe_str(ls, commandraw, &c2); + /* Finish setting up commandraw, for hooks and %u */ + p = command2; + if (attrib) { + safe_chr('/', commandraw, &c2); + safe_str(swp, commandraw, &c2); + } + if (*p && (*p == ' ')) { + safe_chr(' ', commandraw, &c2); + p++; + } + if (cmd->type & CMD_T_ARGS) { + int lsa_index; + if (lsa[1]) { + safe_str(lsa[1], commandraw, &c2); + for (lsa_index = 2; lsa[lsa_index]; lsa_index++) { + safe_chr(',', commandraw, &c2); + safe_str(lsa[lsa_index], commandraw, &c2); + } } - if (cmd->type & CMD_T_EQSPLIT) { - if(rhs_present) { - safe_chr('=', commandraw, &c2); - if (cmd->type & CMD_T_RS_ARGS) { - int rsa_index; - /* This is counterintuitive, but rsa[] - * starts at 1. */ - if (rsa[1]) { - safe_str(rsa[1], commandraw, &c2); - for (rsa_index = 2; rsa[rsa_index]; rsa_index++) { - safe_chr(',', commandraw, &c2); - safe_str(rsa[rsa_index], commandraw, &c2); - } - } + } else { + safe_str(ls, commandraw, &c2); + } + if (cmd->type & CMD_T_EQSPLIT) { + if (rhs_present) { + safe_chr('=', commandraw, &c2); + if (cmd->type & CMD_T_RS_ARGS) { + int rsa_index; + /* This is counterintuitive, but rsa[] + * starts at 1. */ + if (rsa[1]) { + safe_str(rsa[1], commandraw, &c2); + for (rsa_index = 2; rsa[rsa_index]; rsa_index++) { + safe_chr(',', commandraw, &c2); + safe_str(rsa[rsa_index], commandraw, &c2); + } + } } else { + safe_str(rs, commandraw, &c2); } - } else { - safe_str(rs, commandraw, &c2); } + } #ifdef NEVER - /* We used to do this, but we're not sure why */ - process_expression(commandraw, &c2, (const char **) &p, player, realcause, - cause, noevtoken ? PE_NOTHING : - ((PE_DEFAULT & ~PE_FUNCTION_CHECK) | - PE_COMMAND_BRACES), PT_DEFAULT, NULL); + /* We used to do this, but we're not sure why */ + process_expression(commandraw, &c2, (const char **) &p, player, cause, + cause, noevtoken ? PE_NOTHING : + ((PE_DEFAULT & ~PE_EVALUATE) | + PE_COMMAND_BRACES), PT_DEFAULT, NULL); #endif - } - *c2 = '\0'; - } - + *c2 = '\0'; + mush_strncpy(global_eval_context.ucom, commandraw, BUFFER_LEN); + retval = NULL; if (cmd->func == NULL) { do_rawlog(LT_ERR, T("No command vector on command %s."), cmd->name); diff --git a/src/cque.c b/src/cque.c index 94ee972..ed57eb7 100644 --- a/src/cque.c +++ b/src/cque.c @@ -39,6 +39,8 @@ #include "game.h" #include "attrib.h" #include "flags.h" +#include "function.h" +#include "case.h" #include "dbdefs.h" #include "log.h" #include "intmap.h" @@ -1212,6 +1214,166 @@ do_waitpid(dbref player, const char *pidstr, const char *timestr, notify_format(player, T("Queue entry with qid %u updated."), pid); } +FUNCTION(fun_pidinfo) +{ + char *r, *s; + char *osep, osepd[2] = { ' ', '\0' }; + char *fields, field[80] = "queue player time object attribute command"; + uint32_t pid; + BQUE *q; + bool first = true; + + if (!is_uinteger(args[0])) { + safe_str(T(e_num), buff, bp); + return; + } + + pid = parse_uint32(args[0], NULL, 10); + q = im_find(queue_map, pid); + + if (!q) { + safe_str(T("#-1 INVALID PID"), buff, bp); + return; + } + + if (!controls(executor, q->player) && !LookQueue(executor)) { + safe_str(T(e_perm), buff, bp); + return; + } + + if ((nargs > 1) && args[1] && *args[1]) { + fields = args[1]; + } else { + fields = field; + } + + if (nargs == 3) + osep = args[2]; + else { + osep = osepd; + } + + s = trim_space_sep(fields, ' '); + do { + r = split_token(&s, ' '); + if (string_prefix("queue", r)) { + if (!first) + safe_str(osep, buff, bp); + first = false; + if (GoodObject(q->sem)) + safe_str("semaphore", buff, bp); + else + safe_str("wait", buff, bp); + } else if (string_prefix("player", r)) { + if (!first) + safe_str(osep, buff, bp); + first = false; + safe_dbref(q->player, buff, bp); + } else if (string_prefix("time", r)) { + if (!first) + safe_str(osep, buff, bp); + first = false; + if (q->left == 0) + safe_integer(-1, buff, bp); + else + safe_integer(difftime(q->left, mudtime), buff, bp); + } else if (string_prefix("object", r)) { + if (!first) + safe_str(osep, buff, bp); + first = false; + safe_dbref(q->sem, buff, bp); + } else if (string_prefix("attribute", r)) { + if (!first) + safe_str(osep, buff, bp); + first = false; + if (GoodObject(q->sem)) { + safe_str(q->semattr, buff, bp); + } else { + safe_dbref(NOTHING, buff, bp); + } + } else if (string_prefix("command", r)) { + if (!first) + safe_str(osep, buff, bp); + first = false; + safe_str(q->comm, buff, bp); + } + } while (s); +} + +FUNCTION(fun_lpids) +{ + /* Can be called as LPIDS or GETPIDS */ + BQUE *tmp; + int qmask = 3; + dbref thing = -1; + dbref player = -1; + char *attr = NULL; + bool first = true; + if (string_prefix(called_as, "LPIDS")) { + /* lpids(player[,type]) */ + if (args[0] && *args[0]) { + player = match_thing(executor, args[0]); + if (!GoodObject(player)) { + safe_str(T(e_notvis), buff, bp); + return; + } + if (!(LookQueue(executor) || (Owner(player) == executor))) { + safe_str(T(e_perm), buff, bp); + return; + } + } else if (!LookQueue(executor)) { + player = executor; + } + if ((nargs == 2) && args[1] && *args[1]) { + if (*args[1] == 'W' || *args[1] == 'w') + qmask = 1; + else if (*args[1] == 'S' || *args[1] == 's') + qmask = 2; + } + } else { + /* getpids(obj[/attrib]) */ + qmask = 2; /* semaphores only */ + attr = strchr(args[0], '/'); + if (attr) + *attr++ = '\0'; + thing = match_thing(executor, args[0]); + if (!GoodObject(thing)) { + safe_str(T(e_notvis), buff, bp); + return; + } + if (!(LookQueue(executor) || (controls(executor, thing)))) { + safe_str(T(e_perm), buff, bp); + return; + } + } + + if (qmask & 1) { + for (tmp = qwait; tmp; tmp = tmp->next) { + if (GoodObject(player) && (!Owns(tmp->player, player))) + continue; + if (!first) + safe_chr(' ', buff, bp); + safe_integer(tmp->qid, buff, bp); + first = false; + } + } + if (qmask & 2) { + for (tmp = qsemfirst; tmp; tmp = tmp->next) { + if (GoodObject(player) && (!Owns(tmp->player, player))) + continue; + if (GoodObject(thing) && (tmp->sem != thing)) + continue; + if (attr && *attr && strcasecmp(tmp->semattr, attr)) + continue; + if (!first) + safe_chr(' ', buff, bp); + safe_integer(tmp->qid, buff, bp); + first = false; + } + } +} + + static void show_queue(dbref player, dbref victim, int q_type, int q_quiet, int q_all, BQUE * q_ptr, int *tot, int *self, int *del) @@ -1508,7 +1670,6 @@ do_halt(dbref owner, const char *ncom, dbref victim) } add_to(QUEUE_PER_OWNER ? Owner(player) : player, num); - if (ncom && *ncom) { int j; for (j = 0; j < 10; j++) @@ -1603,20 +1764,16 @@ do_haltqid(dbref player, uint32_t qid) turn comes up (Or show it in @ps, etc.). Exception is for semaphores, which otherwise might wait forever. */ q->player = NOTHING; - if (q->semattr) { BQUE *last = NULL, *tmp; - for (tmp = qsemfirst; tmp; last = tmp, tmp = tmp->next) { if (tmp == q) { if (last) last->next = tmp->next; else qsemfirst = tmp->next; - if (qsemlast == tmp) qsemlast = last; - break; } } @@ -1654,7 +1811,6 @@ do_haltpid(dbref player, const char *arg1) } - /** Halt all objects in the database. * \param player the enactor. */ @@ -1687,7 +1843,6 @@ void do_allrestart(dbref player) { dbref thing; - if (!HaltAny(player)) { notify(player, T("You do not have the power to restart the world.")); return; @@ -1700,7 +1855,8 @@ do_allrestart(dbref player) } if (IsPlayer(thing)) { notify_format(thing, - T("Your objects are being globally restarted by %s"), + T + ("Your objects are being globally restarted by %s"), Name(player)); } } @@ -1711,7 +1867,6 @@ do_raw_restart(victim) dbref victim; { dbref thing; - if (IsPlayer(victim)) { for (thing = 0; thing < db_top; thing++) { if ((Owner(thing) == victim) && !IsGarbage(thing) diff --git a/src/create.c b/src/create.c index cb0cbfe..b793b2b 100644 --- a/src/create.c +++ b/src/create.c @@ -103,7 +103,9 @@ do_real_open(dbref player, const char *direction, const char *linkto, dbref loc = (pseudo != - NOTHING) ? pseudo : (IsExit(player) ? Source(player) : Location(player)); + NOTHING) ? pseudo : (IsExit(player) ? Source(player) : (IsRoom(player) ? + player : + Location(player))); dbref new_exit; if (!command_check_byname(player, "@dig")) { notify(player, "Permission denied."); @@ -551,8 +553,10 @@ clone_object(dbref player, dbref thing, const char *newname, int preserve) clone = new_object(); + /* Need to figure out why this is here. */ memcpy(REFDB(clone), REFDB(thing), sizeof(struct object)); Owner(clone) = Owner(player); + Name(clone) = NULL; if (newname && *newname) set_name(clone, newname); else diff --git a/src/db.c b/src/db.c index 7d114a1..ddaa653 100644 --- a/src/db.c +++ b/src/db.c @@ -1017,6 +1017,7 @@ db_paranoid_write(PENNFILE *f, int flag) dbflag += DBF_DIVISIONS; dbflag += DBF_LABELS; dbflag += DBF_SPIFFY_AF_ANSI; + dbflag += DBF_HEAR_CONNECT; do_rawlog(LT_CHECK, "PARANOID WRITE BEGINNING...\n"); @@ -1750,6 +1751,12 @@ db_read_oldstyle(PENNFILE *f) if (IsPlayer(i)) { add_player(i); clear_flag_internal(i, "CONNECTED"); + /* If it has the MONITOR flag and the db predates HEAR_CONNECT, swap them over */ + if (!(globals.indb_flags & DBF_HEAR_CONNECT) && + has_flag_by_name(i, "MONITOR", NOTYPE)) { + clear_flag_internal(i, "MONITOR"); + set_flag_internal(i, "HEAR_CONNECT"); + } } break; @@ -2102,6 +2109,12 @@ db_read(PENNFILE *f) if (IsPlayer(i)) { add_player(i); clear_flag_internal(i, "CONNECTED"); + /* If it has the MONITOR flag and the db predates HEAR_CONNECT, swap them over */ + if (!(globals.indb_flags & DBF_HEAR_CONNECT) && + has_flag_by_name(i, "MONITOR", NOTYPE)) { + clear_flag_internal(i, "MONITOR"); + set_flag_internal(i, "HEAR_CONNECT"); + } } } break; diff --git a/src/function.c b/src/function.c index 070330c..f8e7db3 100644 --- a/src/function.c +++ b/src/function.c @@ -499,6 +499,8 @@ FUNTAB flist[] = { {"LIST", fun_list, 1, 1, FN_REG}, {"LIT", fun_lit, 1, -1, FN_LITERAL}, {"LJUST", fun_ljust, 2, 3, FN_REG}, + {"LLOCKFLAGS", fun_lockflags, 0, 1, FN_REG}, + {"LLOCKS", fun_locks, 1, 1, FN_REG}, {"LMATH", fun_lmath, 2, 3, FN_REG}, {"LNUM", fun_lnum, 1, 3, FN_REG}, {"LOC", fun_loc, 1, 1, FN_REG}, @@ -506,6 +508,9 @@ FUNTAB flist[] = { {"LOCALIZE", fun_localize, 1, 1, FN_NOPARSE}, {"LOCATE", fun_locate, 3, 3, FN_REG}, {"LOCK", fun_lock, 1, 2, FN_REG}, + {"LOCKFLAGS", fun_lockflags, 0, 1, FN_REG}, + {"LOCKOWNER", fun_lockowner, 1, 1, FN_REG}, + {"LOCKS", fun_locks, 1, 1, FN_REG}, {"LPARENT", fun_lparent, 1, 1, FN_REG}, {"LPLAYERS", fun_dbwalker, 1, 1, FN_REG}, {"LPORTS", fun_lports, 0, 1, FN_REG}, diff --git a/src/fundb.c b/src/fundb.c index ac603cf..5d83b51 100644 --- a/src/fundb.c +++ b/src/fundb.c @@ -451,8 +451,6 @@ FUNCTION(fun_flags) return; } safe_str(privs_to_letters(attr_privs_view, AL_FLAGS(a)), buff, bp); - if (atr_sub_branch(a)) - safe_chr('`', buff, bp); } else { /* Object flags, visible to all */ safe_str(unparse_flags(thing, executor), buff, bp); @@ -1130,6 +1128,121 @@ get_locktype(str) return upcasestr(str); } +/* ARGSUSED */ +FUNCTION(fun_locks) +{ + dbref thing = match_thing(executor, args[0]); + lock_list *ll; + const lock_list *p; + int first = 1; + + if (!GoodObject(thing)) { + safe_str(T(e_notvis), buff, bp); + return; + } + + for (ll = Locks(thing); ll; ll = ll->next) { + p = get_lockproto(L_TYPE(ll)); + if (!first) { + safe_chr(' ', buff, bp); + } + first = 0; + if (!p) + safe_str("USER:", buff, bp); + safe_str(L_TYPE(ll), buff, bp); + } +} + +/* ARGSUSED */ +FUNCTION(fun_lockflags) +{ + dbref it; + char *p; + int fullname = 0; + lock_list *ll; + lock_type ltype; + + if (called_as[1] == 'L') /* LLOCKFLAGS */ + fullname = 1; + + if (nargs == 0) { + if (fullname) + list_lock_flags_long(buff, bp); + else + list_lock_flags(buff, bp); + return; + } + + if ((p = strchr(args[0], '/'))) + *(p++) = '\0'; + + it = match_thing(executor, args[0]); + if (!GoodObject(it)) { + safe_str(T(e_notvis), buff, bp); + return; + } + ltype = get_locktype(p); + + if (GoodObject(it) && (ltype !=NULL) + &&Can_Read_Lock(executor, it, ltype)) { + ll = getlockstruct(it, ltype); + if (ll) { + if (fullname) + safe_str(lock_flags_long(ll), buff, bp); + else + safe_str(lock_flags(ll), buff, bp); + return; + } else { + safe_str("#-1 NO SUCH LOCK", buff, bp); + return; + } + } + safe_str("#-1 NO SUCH LOCK", buff, bp); +} + +/* ARGSUSED */ +FUNCTION(fun_lockowner) +{ + dbref it; + char *p; + lock_type ltype; + lock_list *ll; + + if ((p = strchr(args[0], '/'))) + *(p++) = '\0'; + + it = match_thing(executor, args[0]); + if (!GoodObject(it)) { + safe_str(T(e_notvis), buff, bp); + return; + } + ltype = get_locktype(p); + if (ltype == NULL || !Can_Read_Lock(executor, it, ltype)) { + safe_str(T("#-1 NO SUCH LOCK"), buff, bp); + return; + } + ll = getlockstruct(it, ltype); + if (ll) + safe_dbref(L_CREATOR(ll), buff, bp); + else + safe_str(T("#-1 NO SUCH LOCK"), buff, bp); + +} + +/* ARGSUSED */ +FUNCTION(fun_lset) +{ + if (!FUNCTION_SIDE_EFFECTS) { + safe_str(T(e_disabled), buff, bp); + return; + } + if (!command_check_byname(executor, "@lset") || fun->flags & FN_NOSIDEFX) { + safe_str(T(e_perm), buff, bp); + return; + } + do_lset(executor, args[0], args[1]); +} + /* ARGSUSED */ FUNCTION(fun_lock) { diff --git a/src/funlist.c b/src/funlist.c index 56c8c3f..6798d32 100644 --- a/src/funlist.c +++ b/src/funlist.c @@ -1404,6 +1404,14 @@ FUNCTION(fun_randword) s = trim_space_sep(args[0], sep); word_count = do_wordcount(s, sep); + + if (word_count == 0) + return; + else if (word_count == 1) { + safe_strl(args[0], arglens[0], buff, bp); + return; + } + word_index = get_random32(0, word_count - 1); /* Go to the start of the token we're interested in. */ @@ -2080,6 +2088,7 @@ FUNCTION(fun_member) char *s, *t; char sep; int el; + char needle[BUFFER_LEN], haystack[BUFFER_LEN]; if (!delim_check(buff, bp, nargs, args, 3, &sep)) return; @@ -2088,12 +2097,16 @@ FUNCTION(fun_member) safe_str(T("#-1 CAN ONLY TEST ONE ELEMENT"), buff, bp); return; } - s = trim_space_sep(args[0], sep); + + strncpy(haystack, remove_markup(args[0], NULL), BUFFER_LEN); + strncpy(needle, remove_markup(args[1], NULL), BUFFER_LEN); + + s = trim_space_sep(haystack, sep); el = 1; do { t = split_token(&s, sep); - if (!strcmp(args[1], t)) { + if (!strcmp(needle, t)) { safe_integer(el, buff, bp); return; } diff --git a/src/funmath.c b/src/funmath.c index 7405edc..1179aa9 100644 --- a/src/funmath.c +++ b/src/funmath.c @@ -1918,6 +1918,7 @@ FUNCTION(fun_baseconv) while (ptr && *ptr) { if (*ptr == '-') { isnegative = 1; + ptr++; continue; } n *= from; diff --git a/src/funmisc.c b/src/funmisc.c index 1b4c886..3770caf 100644 --- a/src/funmisc.c +++ b/src/funmisc.c @@ -305,25 +305,26 @@ FUNCTION(fun_r) /* ARGSUSED */ FUNCTION(fun_rand) { - /* - * Uses Sh'dow's random number generator, found in utils.c. Better - * distribution than original, w/ minimal speed losses. - */ - int low, high; - if (!is_integer(args[0])) { - safe_str(T(e_int), buff, bp); + uint32_t low, high; + if (!is_strict_uinteger(args[0])) { + safe_str(T(e_uint), buff, bp); return; } if (nargs == 1) { low = 0; - high = parse_integer(args[0]) - 1; + high = parse_uinteger(args[0]); + if (high == 0) { + safe_str(T(e_range), buff, bp); + return; + } + high -= 1; } else { - if (!is_integer(args[1])) { - safe_str(T(e_ints), buff, bp); + if (!is_strict_uinteger(args[1])) { + safe_str(T(e_uints), buff, bp); return; } - low = parse_integer(args[0]); - high = parse_integer(args[1]); + low = parse_uinteger(args[0]); + high = parse_uinteger(args[1]); } if (low > high) { @@ -331,7 +332,7 @@ FUNCTION(fun_rand) return; } - safe_integer(get_random32(low, high), buff, bp); + safe_uinteger(get_random32(low, high), buff, bp); } /* ARGSUSED */ diff --git a/src/funstr.c b/src/funstr.c index ba6ba26..8604afc 100644 --- a/src/funstr.c +++ b/src/funstr.c @@ -1866,7 +1866,6 @@ align_one_line(char *buff, char **bp, int ncols, return 1; } - FUNCTION(fun_align) { int nline; @@ -1954,35 +1953,71 @@ FUNCTION(fun_align) safe_str(T("#-1 TOO MANY COLUMNS FOR ALIGN"), buff, bp); return; } - if (nargs < (ncols + 1) || nargs > (ncols + 4)) { - safe_str(T("#-1 INVALID NUMBER OF ARGUMENTS TO ALIGN"), buff, bp); - return; - } - if (nargs >= (ncols + 2)) { - if (!args[ncols + 1] || strlen(args[ncols + 1]) > 1) { - safe_str(T("#-1 FILLER MUST BE ONE CHARACTER"), buff, bp); + if (strcmp(called_as, "LALIGN")) { + /* each column is a separate arg */ + if (nargs < (ncols + 1) || nargs > (ncols + 4)) { + safe_str(T("#-1 INVALID NUMBER OF ARGUMENTS TO ALIGN"), buff, bp); return; } - if (*args[ncols + 1]) { - filler = *(args[ncols + 1]); + if (nargs >= (ncols + 2)) { + if (!args[ncols + 1] || strlen(args[ncols + 1]) > 1) { + safe_str(T("#-1 FILLER MUST BE ONE CHARACTER"), buff, bp); + return; + } + if (*args[ncols + 1]) { + filler = *(args[ncols + 1]); + } + } + if (nargs >= (ncols + 3)) { + fieldsep = args[ncols + 2]; + } + if (nargs >= (ncols + 4)) { + linesep = args[ncols + 3]; } - } - if (nargs >= (ncols + 3)) { - fieldsep = args[ncols + 2]; - } - if (nargs >= (ncols + 4)) { - linesep = args[ncols + 3]; - } - fslen = strlen(fieldsep); - lslen = strlen(linesep); + fslen = strlen(fieldsep); + lslen = strlen(linesep); - for (i = 0; i < MAX_COLS; i++) { - as[i] = NULL; - } - for (i = 0; i < ncols; i++) { - as[i] = parse_ansi_string(args[i + 1]); - ptrs[i] = as[i]->text; + for (i = 0; i < MAX_COLS; i++) { + as[i] = NULL; + } + for (i = 0; i < ncols; i++) { + as[i] = parse_ansi_string(args[i + 1]); + ptrs[i] = as[i]->text; + } + } else { + /* columns are in args[1] as an args[2]-separated list */ + char delim, *s; + if (!delim_check(buff, bp, nargs, args, 3, &delim)) + return; + if (do_wordcount(args[1], delim) != ncols) { + safe_str(T("#-1 INVALID NUMBER OF ARGUMENTS TO ALIGN"), buff, bp); + return; + } + if (nargs > 3) { + if (!args[3] || strlen(args[3]) > 1) { + safe_str(T("#-1 FILLER MUST BE ONE CHARACTER"), buff, bp); + return; + } + if (*args[3]) + filler = *(args[3]); + } + if (nargs > 4) + fieldsep = args[4]; + if (nargs > 5) + linesep = args[5]; + + fslen = strlen(fieldsep); + lslen = strlen(linesep); + + for (i = 0; i < MAX_COLS; i++) { + as[i] = NULL; + } + s = trim_space_sep(args[1], delim); + for (i = 0; i < ncols; i++) { + as[i] = parse_ansi_string(split_token(&s, delim)); + ptrs[i] = as[i]->text; + } } nline = 0; diff --git a/src/game.c b/src/game.c index 80f6644..ef31f49 100644 --- a/src/game.c +++ b/src/game.c @@ -1246,8 +1246,8 @@ process_command(dbref player, char *command, dbref cause, dbref realcause, int strcpy(unp, command); cptr = command_parse(player, cause, realcause, command, from_port); - strcpy(global_eval_context.ucom, (cptr ? cptr : "")); if (cptr) { + mush_strncpy(global_eval_context.ucom, cptr, BUFFER_LEN); a = 0; if (!Gagged(player)) { if (Mobile(player)) { @@ -1566,7 +1566,7 @@ Listener(dbref thing) /* If a monitor flag is set on a room or thing, it's a listener. * Otherwise not (even if ^patterns are present) */ - return (ThingListen(thing) || RoomListen(thing)); + return has_flag_by_name(thing, "MONITOR", NOTYPE); } /** Reset all players' money. @@ -2320,7 +2320,8 @@ db_open(const char *fname) pf->type = PFT_GZFILE; pf->handle.g = gzopen(filename, "rb"); if (!pf->handle.g) { - do_rawlog(LT_ERR, "Unable to open %s with libz: %s\n", filename, strerror(errno)); + do_rawlog(LT_ERR, "Unable to open %s with libz: %s\n", filename, + strerror(errno)); mush_free(pf, "pennfile"); longjmp(db_err, 1); } diff --git a/src/lock.c b/src/lock.c index 552443e..54fc71f 100644 --- a/src/lock.c +++ b/src/lock.c @@ -144,7 +144,6 @@ static void free_one_lock_list(lock_list *ll); static lock_type check_lock_type(dbref player, dbref thing, lock_type name); static int delete_lock(dbref player, dbref thing, lock_type type); static int can_write_lock(dbref player, dbref thing, lock_list *lock); -static lock_list *getlockstruct(dbref thing, lock_type type); static lock_list *getlockstruct_noparent(dbref thing, lock_type type); slab *lock_slab = NULL; @@ -153,6 +152,8 @@ static void free_lock(lock_list *ll); extern int unparsing_boolexp; +lock_list *getlockstruct(dbref thing, lock_type type); + /** Return a list of all available locks * \param buff the buffer * \param bp a pointer to the current position in the buffer @@ -212,6 +213,39 @@ lock_flags(lock_list *ll) return privs_to_letters(lock_privs, L_FLAGS(ll)); } +/** List all lock flag characters on a buffer + * \param buff The buffer + * \param bp Pointer to a position in the buffer. + */ + +void +list_lock_flags(char *buff, char **bp) +{ + int i; + for (i = 0; lock_privs[i].name; i++) { + if (lock_privs[i].letter) + safe_chr(lock_privs[i].letter, buff, bp); + } +} + +/** List all lock flag names on a buffer + * \param buff The buffer + * \param bp Pointer to a position in the buffer. + */ + +void +list_lock_flags_long(char *buff, char **bp) +{ + int i; + int first = 1; + for (i = 0; lock_privs[i].name; i++) { + if (!first) + safe_chr(' ', buff, bp); + first = 0; + safe_str(lock_privs[i].name, buff, bp); + } +} + /** Return a list of lock flag names. * \param ll pointer to a lock. * \return string of lock flag names, space-separated. @@ -335,7 +369,7 @@ getlock_noparent(dbref thing, lock_type type) return L_KEY(ll); } -static lock_list * +lock_list * getlockstruct(dbref thing, lock_type type) { lock_list *ll; diff --git a/src/markup.c b/src/markup.c index 9710c24..a52a599 100644 --- a/src/markup.c +++ b/src/markup.c @@ -2102,6 +2102,7 @@ real_decompose_str(char *orig, char *buff, char **bp) * \param ovector the offset vectors * \param stringcount the number of subpatterns * \param stringnumber the number of the desired subpattern + * \param nonempty if true, copy empty registers as well. * \param buff buffer to copy the subpattern to * \param bp pointer to the end of buffer * \return size of subpattern, or -1 if unknown pattern @@ -2130,6 +2131,7 @@ ansi_pcre_copy_substring(ansi_string *as, int *ovector, * \param ovector the offset vectors * \param stringcount the number of subpatterns * \param stringname the name of the desired subpattern + * \param nonempty if true, copy empty registers as well. * \param buff buffer to copy the subpattern to * \param bp pointer to the end of buffer * \return size of subpattern, or -1 if unknown pattern diff --git a/src/mysocket.c b/src/mysocket.c index d73c48f..ccdf9a2 100644 --- a/src/mysocket.c +++ b/src/mysocket.c @@ -318,6 +318,17 @@ make_socket(Port_t port, int socktype, union sockaddr_u *addr, socklen_t * len, if (bind(s, server->ai_addr, server->ai_addrlen) == 0) break; /* Success */ +#ifdef WIN32 + if (WSAGetLastError() == WSAEADDRINUSE) { +#else + if (errno == EADDRINUSE) { +#endif + fprintf(stderr, + "Another process (Possibly another copy of this mush?) appears to be using port %hu. Aborting.\n", + port); + exit(1); + } + penn_perror("binding stream socket (Possibly ignorable)"); closesocket(s); } while ((server = server->ai_next) != NULL); diff --git a/src/notify.c b/src/notify.c index 487d444..8665716 100644 --- a/src/notify.c +++ b/src/notify.c @@ -953,7 +953,7 @@ notify_anything_loc(dbref speaker, na_lookup func, * * unlike normal @listen, don't pass the message on. * */ - if ((ThingListen(target) || RoomListen(target)) + if ((has_flag_by_name(target, "MONITOR", NOTYPE)) && eval_lock(speaker, target, Listen_Lock) ) atr_comm_match(target, speaker, '^', ':', diff --git a/src/parse.c b/src/parse.c index 6b25ca1..e3334bc 100644 --- a/src/parse.c +++ b/src/parse.c @@ -334,6 +334,32 @@ is_uinteger(char const *str) return 1; } +/** Is string really an unsigned integer? + * \param str string to check. + * \retval 1 string is an uinteger. + * \retval 0 string is not an uinteger. + */ +bool +is_strict_uinteger(const char *str) +{ + char *end; + + if (!str) + return 0; + /* strtoul() accepts negative numbers, so we still have to do this check */ + while (isspace((unsigned char) *str)) + str++; + if (*str == '\0') + return 0; + if (!(isdigit((unsigned char) *str) || *str == '+')) + return 0; + errno = 0; + parse_uint(str, &end, 10); + if (errno == ERANGE || *end != '\0') + return 0; + return 1; +} + /** Is string a number by the strict definition? * A strict number is a non-null string that passes strtod. * \param str string to check. diff --git a/src/pcre.c b/src/pcre.c index f9d5f23..854c368 100644 --- a/src/pcre.c +++ b/src/pcre.c @@ -1257,6 +1257,7 @@ int + pcre_get_substring_list(const char *subject, int *ovector, int stringcount, const char ***listptr); @@ -1347,6 +1348,7 @@ int + pcre_get_substring(const char *subject, int *ovector, int stringcount, int stringnumber, const char **stringptr); @@ -1404,6 +1406,7 @@ int + pcre_get_named_substring(const pcre * code, const char *subject, int *ovector, int stringcount, const char *stringname, const char **stringptr); @@ -2291,6 +2294,7 @@ static BOOL + compile_regex(int, int, int *, uschar **, const uschar **, int *, BOOL, int, int *, int *, branch_chain *, compile_data *); diff --git a/src/predicat.c b/src/predicat.c index 4ef128e..02e4efe 100644 --- a/src/predicat.c +++ b/src/predicat.c @@ -883,6 +883,9 @@ int ok_password(const char *password) { const unsigned char *scan; + if (password == NULL) + return 0; + if (*password == '\0') return 0; diff --git a/src/set.c b/src/set.c index d1d13dc..cea38ae 100644 --- a/src/set.c +++ b/src/set.c @@ -59,55 +59,61 @@ static void copy_attrib_flags(dbref player, dbref target, ATTR *atr, int flags); * \param newname new name for object. */ void -do_name(dbref player, const char *name, char *newname) +do_name(dbref player, const char *name, char *newname_) { dbref thing; char *eon; /* End Of Name */ + char *bon; /* Beginning of name*/ char *myenv[10]; int i; - - newname = trim_space_sep(newname, ' '); + char *newname; if ((thing = match_controlled(player, name)) != NOTHING) { + newname = mush_strdup(trim_space_sep(newname_, ' '), "name.newname"); + bon = newname; + /* check for bad name */ if ((*newname == '\0') || strchr(newname, '[')) { notify(player, T("Give it what new name?")); + mush_free(newname, "name.newname"); return; } /* check for renaming a player */ if (IsPlayer(thing)) { - if (*newname == '"') { - for (; *newname && ((*newname == '"') - || isspace((unsigned char) *newname)); newname++) ; - eon = newname; - while (*eon && (*eon != '"')) { - while (*eon && (*eon != '"')) - eon++; - if (*eon == '"') { - *eon++ = '\0'; - while (*eon && isspace((unsigned char) *eon)) - eon++; - break; - } + // If it has "s, it's surrounding a spaced name, likely. So bon + // is beginning of name. + // I'm going to cheat here and make it so + // @name me="foo"bar names somebody foo, since " is an invalid name. + if (*bon == '"') { + bon++; + eon = bon; + while (*eon && *eon != '"') { + eon++; + } + if (*eon) { + *eon = '\0'; } } else { - eon = newname; + eon = bon; while (*eon && !isspace((unsigned char) *eon)) eon++; if (*eon) - *eon++ = '\0'; + *(eon++) = '\0'; } - if (!ok_player_name(newname, player, thing)) { + if (!ok_player_name(bon, player, thing)) { notify(player, T("You can't give a player that name.")); + mush_free(newname, "name.newname"); return; } /* everything ok, notify */ do_log(LT_CONN, 0, 0, T("Name change by %s(#%d) to %s"), - Name(thing), thing, newname); + Name(thing), thing, bon); /* everything ok, we can fall through to change the name */ } else { + bon = newname; if (!ok_name(newname)) { notify(player, T("That is not a reasonable name.")); + mush_free(newname, "name.newname"); return; } } @@ -116,13 +122,13 @@ do_name(dbref player, const char *name, char *newname) myenv[0] = (char *) mush_malloc(BUFFER_LEN, "string"); myenv[1] = (char *) mush_malloc(BUFFER_LEN, "string"); mush_strncpy(myenv[0], Name(thing), BUFFER_LEN); - strcpy(myenv[1], newname); + strcpy(myenv[1], bon); for (i = 2; i < 10; i++) myenv[i] = NULL; if (IsPlayer(thing)) - reset_player_list(thing, Name(thing), NULL, newname, NULL); - set_name(thing, newname); + reset_player_list(thing, Name(thing), NULL, bon, NULL); + set_name(thing, bon); if(!IsPlayer(thing)) { char lmbuf[1024]; ModTime(thing) = mudtime; @@ -137,6 +143,7 @@ do_name(dbref player, const char *name, char *newname) notify(player, T("Name set.")); real_did_it(player, thing, NULL, NULL, "ONAME", NULL, "ANAME", NOTHING, myenv, NA_INTER_PRESENCE); + mush_free(newname, "name.newname"); mush_free(myenv[0], "string"); mush_free(myenv[1], "string"); } @@ -981,7 +988,7 @@ do_use(dbref player, const char *what) if ((thing = noisy_match_result(player, what, TYPE_THING, - MAT_NEAR_THINGS)) != NOTHING) { + MAT_NEAR_THINGS | MAT_ENGLISH)) != NOTHING) { if (!eval_lock(player, thing, Use_Lock)) { fail_lock(player, thing, Use_Lock, T("Permission denied."), NOTHING); return; diff --git a/src/wild.c b/src/wild.c index 0dea11d..dac70c9 100644 --- a/src/wild.c +++ b/src/wild.c @@ -544,11 +544,13 @@ regexp_match_case_r(const char *restrict s, const char *restrict val, bool cs, pcre_extra *extra; size_t i; const char *errptr; + ansi_string *as; const char *d; size_t delenn; int erroffset; int offsets[99]; int subpatterns; + int totallen = 0; for (i = 0; i < nmatches; i++) matches[i] = NULL; @@ -563,14 +565,20 @@ regexp_match_case_r(const char *restrict s, const char *restrict val, bool cs, return 0; } add_check("pcre"); - d = remove_markup(val, &delenn); + + /* The ansi string */ + as = parse_ansi_string(val); + delenn = as->len; + d = as->text; + extra = default_match_limit(); /* * Now we try to match the pattern. The relevant fields will * automatically be filled in by this. */ - if ((subpatterns = pcre_exec(re, extra, d, delenn - 1, 0, 0, offsets, 99)) + if ((subpatterns = pcre_exec(re, extra, d, delenn, 0, 0, offsets, 99)) < 0) { + free_ansi_string(as); mush_free(re, "pcre"); return 0; } @@ -586,20 +594,26 @@ regexp_match_case_r(const char *restrict s, const char *restrict val, bool cs, * go from 1 to 9. We DO PRESERVE THIS PARADIGM, for consistency * with other languages. */ - - for (i = 0; i < nmatches && (int) i < subpatterns && (size_t) len > i; i++) { - ssize_t sublen; - - sublen = pcre_copy_substring(d, offsets, subpatterns, (int) i, data, len); - - if (sublen < 0) - break; - - matches[i] = data; - data += sublen + 2; - len -= sublen + 2; + for (i = 0; i < nmatches && (int) i < subpatterns && totallen < len; i++) { + // Current data match. + /* This is more annoying than a jumping flea up the nose. Since + * ansi_pcre_copy_substring() uses buff, bp instead of char *, len, + * we have to mangle bp and 'buff' by hand. Sound easy? We also + * have to make sure that 'buff' + len < BUFFER_LEN. Particularly since + * matchspace is 2*BUFFER_LEN + */ + char *buff = data + totallen; + char *bp = buff; + matches[i] = bp; + if ((len - totallen) < BUFFER_LEN) { + buff = data + len - BUFFER_LEN; + } + ansi_pcre_copy_substring(as, offsets, subpatterns, (int) i, 1, buff, &bp); + *(bp++) = '\0'; + totallen = bp - data; } + free_ansi_string(as); mush_free(re, "pcre"); return 1; } diff --git a/src/wiz.c b/src/wiz.c index 6470e5c..0077df9 100644 --- a/src/wiz.c +++ b/src/wiz.c @@ -1368,34 +1368,6 @@ FUNCTION(fun_lsearch) mush_free(results, "search_results"); } - -#ifdef WIN32 -#pragma warning( disable : 4761) /* Disable bogus conversion warning */ -#endif -/* ARGSUSED */ -FUNCTION(fun_hidden) -{ - dbref it = match_thing(executor, args[0]); - if (CanSee(executor, it) && ((Admin(executor) || - Location(executor) == Location(it) || Location(it) == executor))) { - if ((it == NOTHING) || (!IsPlayer(it))) { - notify(executor, T("Couldn't find that player.")); - safe_str("#-1", buff, bp); - return; - } - safe_boolean(hidden(it), buff, bp); - return; - } else { - notify(executor, T("Permission denied.")); - safe_str("#-1", buff, bp); - return; - } -} - -#ifdef WIN32 -#pragma warning( default : 4761) /* Re-enable conversion warning */ -#endif - /* ARGSUSED */ FUNCTION(fun_quota) { @@ -2016,13 +1988,6 @@ raw_search(dbref player, const char *owner, int nargs, const char **args, ATTR *a; char lbuff[BUFFER_LEN]; - /* make sure player has money to do the search */ - if (!payfor(player, FIND_COST)) { - notify_format(player, T("Searches cost %d %s."), FIND_COST, - ((FIND_COST == 1) ? MONEY : MONIES)); - return -1; - } - if (fill_search_spec(player, owner, nargs, args, &spec) < 0) { giveto(player, FIND_COST); if (spec.lock != TRUE_BOOLEXP) @@ -2030,6 +1995,17 @@ raw_search(dbref player, const char *owner, int nargs, const char **args, return -1; } + /* make sure player has money to do the search - + * But only if this does an eval or lock search. */ + if ((spec.lock != TRUE_BOOLEXP) || + spec.cmdstring[0] || spec.listenstring[0] || spec.eval[0]) { + if (!payfor(player, FIND_COST)) { + notify_format(player, T("Searches cost %d %s."), FIND_COST, + ((FIND_COST == 1) ? MONEY : MONIES)); + return -1; + } + } + if ((spec.owner != ANY_OWNER && spec.owner != Owner(player) && (!(CanSearch(player, spec.owner) || (spec.type == TYPE_PLAYER)) diff --git a/test/testrand.pl b/test/testrand.pl index fdeefdd..f40a961 100644 --- a/test/testrand.pl +++ b/test/testrand.pl @@ -7,4 +7,9 @@ test('rand.5', $god, 'think rand(0,0)', '0'); test('rand.6', $god, 'think rand(1,1)', '1'); test('rand.7', $god, 'think rand(2,1)', '#-1'); test('rand.8', $god, 'think rand(0,9)', '^\d\s*$'); +test('rand.9', $god, 'think rand(-5, 10)', '#-1'); +test('rand.10', $god, 'think rand(-5, -10)', '#-1'); +test('randword.1', $god, 'think randword(%b%b%b)', '^$'); +test('randword.2', $god, 'think randword(foo)', 'foo'); +test('randword.3', $god, 'think randword(foo bar)', '(?:foo|bar)');