From: Rick L Bird Date: Fri, 22 Apr 2011 17:39:37 +0000 (-0400) Subject: PennMUSH Enhancements 1.8.3p7 Applied. X-Git-Url: https://git.theari.com/?a=commitdiff_plain;h=8f81333e36773d89571172d21b5f92874194e6b1;p=cobramush.git PennMUSH Enhancements 1.8.3p7 Applied. This commit refs #69, #70, #71, #72, #73, #74, #75, #76, #77, #78 Also refs #79, #80, #81, #82, #83, #84, #85, #86, #87, #88, #89, #90, And refs #91, and #92 --- diff --git a/COPYRITE b/COPYRITE index b5631d8..083ef3c 100644 --- a/COPYRITE +++ b/COPYRITE @@ -176,3 +176,72 @@ * of CobraMUSH derived from or inspired by PennMUSH, TinyMUSH 2.0, * TinyMUSH 2.2, or TinyMUD. */ + + IV: Additional Copyrights + ++ Penn includes the SIMD-oriented Fast Mersenne Twister PRNG: + +Copyright (c) 2006,2007 Mutsuo Saito, Makoto Matsumoto and Hiroshima +University. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of the Hiroshima University nor the names of + its contributors may be used to endorse or promote products + derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ++ Penn includes a heavily modified old version of the Perl Compatible +Regular Expression library: + + Written by Philip Hazel + Copyright (c) 1997-2005 University of Cambridge + +----------------------------------------------------------------------------- +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of the University of Cambridge nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +----------------------------------------------------------------------------- + diff --git a/config.h.in b/config.h.in index f6b09a3..d8d1395 100644 --- a/config.h.in +++ b/config.h.in @@ -78,6 +78,10 @@ #undef HAVE_LIBFAM +#undef HAVE_ZLIB_H + +#undef HAVE_LIBZ + /* C99ish headers. The first two are really really nice to have. */ #undef HAVE_STDINT_H @@ -265,6 +269,9 @@ typedef void Free_t; #undef HAVE__VSNPRINTF_S +#undef HAVE_VASPRINTF + +#undef HAVE_STRCHRNUL #undef HAVE_STRDUP @@ -304,7 +311,7 @@ typedef void Free_t; #undef HAVE_EPOLL_CTL -#undef HAVE_VALLOC +#undef HAVE_POSIX_MEMALIGN #undef HAVE_WRITEV @@ -320,6 +327,10 @@ typedef void Free_t; #undef HAVE_PWRITE +#undef HAVE_POSIX_FADVISE + +#undef HAVE_POSIX_FALLOCATE + /* Variables and defines */ #undef HAVE_H_ERRNO @@ -340,6 +351,8 @@ typedef void Free_t; #undef DONT_TRANSLATE +#undef INFO_SLAVE + #undef HAVE_UPTIME /* Path to uptime */ @@ -350,6 +363,9 @@ typedef void Free_t; /* Path to sendmail */ #undef SENDMAIL +#undef HAVE_ED +#undef ED_PATH + #undef HAVE_SAFE_TOUPPER /* Optional language features */ @@ -370,6 +386,20 @@ typedef void Free_t; #undef GCC_MALLOC_CALL + +/* Turn on SSE2 stuff automatically if supported (IE, x86-64 or x86 with the right -march switch) */ +#undef HAVE_SSE2 +#ifdef __SSE2__ +#define HAVE_SSE2 +#endif + +#undef HAVE_SSE3 +#ifdef __SSE3__ +#define HAVE_SSE3 +#endif + +#undef HAVE_ALTIVEC + /* TODO: Change in source */ #define RESTRICT restrict diff --git a/configure.ac b/configure.ac index 5aa4dc9..8086f71 100644 --- a/configure.ac +++ b/configure.ac @@ -79,10 +79,7 @@ CFLAGS="-g $CFLAGS -W" fi fi -AX_GCC_OPTION([-fstack-protector], [], [], [ - CFLAGS="$CFLAGS -fstack-protector" -], []) - +# Reduce the size of the binary on PowerPC OS X case "${build_cpu}-${build_os}" in powerpc*-darwin*) AX_GCC_OPTION([-mdynamic-no-pic], [], [], [ @@ -91,6 +88,20 @@ case "${build_cpu}-${build_os}" in ;; esac + +# Some useful security-related compiler, assembler and linker options +AX_GCC_OPTION([-fstack-protector], [], [], [ + CFLAGS="$CFLAGS -fstack-protector" +], []) +AX_LD_CHECK_FLAG([-Wl,-z,noexecstack], [], [], [ + LDFLAGS="$LDFLAGS -Wl,-z,noexecstack" +], []) +AX_LD_CHECK_FLAG([-Wa,--noexecstack], [], [], [ + CFLAGS="$CFLAGS -Wa,--noexecstack" +], []) + + + if test "${CTAGS+set}" != "set" -a "${EXCTAGS+set}" = "set"; then CTAGS=$EXCTAGS fi @@ -105,13 +116,19 @@ if test "${UPTIME+set}" = "set"; then AC_DEFINE_UNQUOTED([UPTIME], "$UPTIME") fi -AC_ARG_VAR(SENDMAIL, Path to sendmail) +AC_ARG_VAR(SENDMAIL, [Path to sendmail]) AC_PATH_PROG(SENDMAIL, sendmail) if test "${SENDMAIL+set}" = "set"; then AC_DEFINE([HAVE_SENDMAIL]) AC_DEFINE_UNQUOTED([SENDMAIL], "$SENDMAIL") fi +AC_ARG_VAR(ED, [Path to ed]) +AC_PATH_PROG(ED, ed) +if test "${ED+set}" = "set"; then + AC_DEFINE([HAVE_ED]) + AC_DEFINE_UNQUOTED([ED_PATH], "$ED -s") +fi ### Headers # Usually there's no need to check for standard C89 headers. @@ -142,6 +159,8 @@ AC_CHECK_HEADER(sys/stat.h, [AC_DEFINE(I_SYS_STAT)]) AC_CHECK_HEADER(sys/types.h, [AC_DEFINE(I_SYS_TYPES)]) AC_CHECK_HEADERS([sys/un.h ieeefp.h sys/resource.h sys/event.h sys/uio.h]) AC_CHECK_HEADERS([poll.h sys/epoll.h sys/select.h sys/inotify.h fam.h]) +AC_CHECK_HEADERS([zlib.h]) + ### C language support # Only need to check C99 and GNU extensions @@ -181,6 +200,7 @@ AC_CHECK_LIB(intl, gettext) AC_CHECK_LIB(crypt, crypt) LIB_SOCKET_NSL AC_CHECK_LIB(fam, FAMOpen) +AC_CHECK_LIB(z, gzungetc) # with_ssl=set CHECK_SSL @@ -242,9 +262,9 @@ AC_FUNC_SETPGRP fi AC_CHECK_FUNCS([cbrt log2 round imaxdiv]) AC_CHECK_FUNCS([getuid geteuid seteuid getpriority setpriority]) -AC_CHECK_FUNCS([socketpair sigaction sigprocmask valloc writev]) +AC_CHECK_FUNCS([socketpair sigaction sigprocmask posix_memalign writev]) AC_CHECK_FUNCS([fcntl pselect poll ppoll pollts kqueue epoll_ctl inotify_init]) -AC_CHECK_FUNCS([pread pwrite]) +AC_CHECK_FUNCS([pread pwrite posix_fadvise posix_fallocate]) AC_FUNC_SNPRINTF if test "x$ac_cv_have_working_snprintf" = xyes; then @@ -253,11 +273,11 @@ fi if test "x$ac_cv_have_working_vsnprintf" = xyes; then AC_DEFINE(HAS_VSNPRINTF) fi -AC_CHECK_FUNCS(_vsnprintf_s) +AC_CHECK_FUNCS([_vsnprintf_s vasprintf]) AC_CHECK_FUNCS([strcasecmp strncasecmp _stricmp _strnicmp strdup]) AC_FUNC_STRCOLL -AC_CHECK_FUNCS([strxfrm _strncoll _stricoll _strnicoll strdup]) +AC_CHECK_FUNCS([strxfrm _strncoll _stricoll _strnicoll strchrnul]) AC_CHECK_FUNC(sysconf, [AC_DEFINE(HAS_SYSCONF)]) AC_CHECK_FUNC(textdomain, [AC_DEFINE(HAS_TEXTDOMAIN)]) @@ -339,9 +359,95 @@ if test "$enable_nls" = "no"; then AC_DEFINE(DONT_TRANSLATE) fi +AC_ARG_ENABLE(info_slave, AS_HELP_STRING([--disable-info_slave], + [Don't use a separate process for hostname lookups]), + enable_info_slave=$enableval, enable_info_slave=yes) +if test "$enable_info_slave" = yes; then + AC_SUBST(INFO_SLAVE_TARGET, info_slave) + AC_DEFINE(INFO_SLAVE) +fi + +AC_ARG_ENABLE(sse2, AS_HELP_STRING([--enable-sse2], + [Use SSE2 instructions (Requires a CPU that supports SSE2)])) +AC_ARG_ENABLE(sse3, AS_HELP_STRING([--enable-sse3], + [Use SSE3 instructions (Requires a CPU that supports SSE3)])) +AC_ARG_ENABLE(altivec, AS_HELP_STRING([--enable-altivec], + [Use PowerPC Altivec instructions (Requires a CPU that supports Altivec)])) + +if test "$enable_sse2" = yes; then + AC_DEFINE(HAVE_SSE2) + CFLAGS="$CFLAGS -msse2" +fi + +if test "$enable_sse3" = yes; then + AC_DEFINE(HAVE_SSE2) + AC_DEFINE(HAVE_SSE3) + CFLAGS="$CFLAGS -msse2 -msse3" +fi + +if test "$enable_altivec" = yes; then + AC_DEFINE(HAVE_ALTIVEC) + CFLAGS="$CFLAGS -maltivec -faltivec" +fi + ### Output +if test ${PCRE_LIBS+set} = set; then + which_pcre="System" +else + which_pcre="Local (Consider getting your sysadmin to install pcre)" +fi + + +echo "Configuration summary:" +echo "* Compiler: $CC" +echo "* Compiler flags: $CFLAGS" +echo "* PCRE: $which_pcre" +if test "$enable_sql" = yes; then + sql_servers="" + if test "$found_mysql" = yes; then + sql_servers+="MySQL " + fi + if test "$found_postgresql" = yes; then + sql_servers+="Postgres " + fi + if test "$found_sqlite" = yes; then + sql_servers+="Sqlite3 " + fi + echo "* SQL support: ${sql_servers:-No}" +else + echo "* SQL support: No" +fi + +if test "$HAVE_SSL" = yes; then + echo "* SSL support: Yes" +else + echo "* SSL support: No" +fi + +if test "$enable_info_slave" = yes; then + echo "* Info slave will be used for hostname lookups." +else + echo "* Hostname lookups will be done by the mush process." +fi + +if test "$enable_nls" = yes -a "${ac_cv_lib_intl_gettext:+set}" = set; then + echo "* Translation support: Yes" +else + echo "* Translation support: No" +fi + +if test "$enable_ipv6" = yes; then + echo "* IPv6 sockets will be used if possible." +else + echo "* Sockets are limited to IPv4" +fi + + + AC_CONFIG_FILES([Makefile src/Makefile]) AC_CONFIG_FILES([game/txt/compose.sh], [chmod +x game/txt/compose.sh]) AC_CONFIG_FILES([test/alltests.sh], [chmod +x test/alltests.sh]) AC_OUTPUT + + diff --git a/game/mushcnf.dst b/game/mushcnf.dst index c806c67..76a9d67 100644 --- a/game/mushcnf.dst +++ b/game/mushcnf.dst @@ -63,6 +63,10 @@ flag_database data/flagdb #compress_suffix # # Use these 3 lines for gzip compression +# Note: If the mush is built with zlib and you use plain 'gzip' and +# 'gunzip', the library will be used instead of external programs. If +# you want to force using the programs, just specify the full path to +# them; e.g. /usr/bin/gzip #compress_program gzip #uncompress_program gunzip #compress_suffix .gz @@ -157,6 +161,15 @@ chunk_swap_file data/chunkswap # gain some locality benefits and overhead savings. chunk_cache_memory 1000000 +# The amount of space, in kibibytes, to initially allocate for the +# swap file. The swap file may grow bigger than this figure, but won't +# shrink to less. Only works on some OSes; ignored on those that don't +# support the posix_fallocate() system call. +# For best results, set it to a larger value than the size of your +# swap file is after the game has been running for a while. How much +# larger depends on how fast the database is growing. +chunk_swap_initial_size 2048 + # The number of attributes that may be moved at one time, once per # second. The higher the value, the faster memory gets defragmented, # but at a greater CPU cost. diff --git a/game/txt/hlp/cobra_chat.hlp b/game/txt/hlp/cobra_chat.hlp index 5d655cc..dbe5724 100644 --- a/game/txt/hlp/cobra_chat.hlp +++ b/game/txt/hlp/cobra_chat.hlp @@ -167,6 +167,93 @@ See also: chat /brief switch is included, players on the channel aren't listed. @channel/chown allows a Wizard to change the owner of a channel. + See "help @channel6" for more. +& @channel6 + @channel/mogrifier = + + The Mogrifier lets you tweak every aspect of a channel's output, before + it goes to individual players' @chatformats. + + must be an object that you control, and it can have any or all + of these attributes which are evaluated when channel messages are generated. + + Before it begins Mogrifying, its MOGRIFY`BLOCK is called, using the same + arguments as @chatformat. If MOGRIFY`BLOCK returns a non-empty string, then + the resultant string is sent to the player, and the message is not + broadcasted. + + A number of separate mogrifiers can be used. Check "help @chat mogrifying" + for details. + + After all of these are called, MOGRIFY`FORMAT is called. It has the exact + same use as @chatformat, but is on a channel-wide level. It receives all + mogrified text (if any), so is generally intended only for reformatting the + whole channel text. It is also overridden by individual @chatformats. + + See "help @chat mogrifying" for examples. +& @chat mogrifying +Mogrifying individual pieces of the channel chatter text: + + If any of these evaluate to a non-null string, they replace that portion + of the chat message. + + %0 - (Depends on the mogrifier.) + %1 - Channel name (unmogrified). + %2 - Chat type (", :, ;, |) + %3 - Message. + %4 - Player chan title. + %5 - Player name. + + MOGRIFY`CHANNAME: %0 = default channel display. (e.g: ""). + MOGRIFY`TITLE: %0 = The player's title, if any. + MOGRIFY`PLAYERNAME: %0 = The player's name. + MOGRIFY`SPEECHTEXT: %0 = "says" + MOGRIFY`MESSAGE: %0 = + + See "help @chat mogrifying2" for examples. +& @chat mogrifying2 +For Talk Like a Pirate Day (Sep 19): + +> @create Pirate Filter +> @chan/mogrifier public=Pirate Filter +> &MOGRIFY`BLOCK Pirate Filter=if(regmatch(%5,ninja),We don't need no ninjas!) +> &MOGRIFY`TITLE Pirate Filter=switch(poss(%#),her,Wench,Buccaneer) +> &MOGRIFY`SPEECHTEXT Pirate Filter=yo-hos +> &MOGRIFY`MESSAGE Pirate Filter=edit(%0,r,rrr) +> &MOGRIFY`CHANNAME Pirate Filter=(%1-Yarr!) + +Output: + +> +public Hello +(Public-Yarr!) Buccaneer Walker yo-hos, "Hello" + +> +public :thinks it's talk like a pirate day? +(Public-Yarr!) Buccaneer Walker thinks it's talk like a pirrrate day? + +> +public Pirates suck, Ninjas are better! +We don't need no ninjas! +(And the message is blocked, won't be sent out). + + See "help @chat mogrifying3" for another example. +& @chat mogrifying3 +For keeping a channel PG and safe, and altering the channel name from + to [Public], with a green "Public". + +> @create PG Channel Mogrifier +> @chan/mogrifier public=PG Channel Mogrifier +> &BADWORDS PG=list of bad words +> &MOGRIFY`MESSAGE PG=regeditall(%0,\\b([edit(v(badwords),%b,|)])\\b,***) +> &MOGRIFY`CHANNAME PG=\[[ansi(g,%1)]\] +> &MOGRIFY`title PG=if(strlen(%0),\(%0\)) + +Output: (With a channel title of "Fast") ("Public" is green) +> +p Hello +[Public] (Fast) Walker says, "hello" +> +p what the list is going on bad bad? +[Public] (Fast) Walker says, "what the *** is going on *** ***?" + +Combine MOGRIFY`FORMAT with speak() and you can have plenty of fun: +On-channel language systems and more! & channel-list Here's the legend for reading the @channel/list output: diff --git a/game/txt/hlp/cobra_cmd.hlp b/game/txt/hlp/cobra_cmd.hlp index 8d6434f..374657a 100644 --- a/game/txt/hlp/cobra_cmd.hlp +++ b/game/txt/hlp/cobra_cmd.hlp @@ -673,7 +673,7 @@ See also: @create @config/attribs @config/flags @config/list[/lowercase] [] - @config/set option=value + @config/set|save option=value This command lists the MUSH configuration parameters, indicating what special things are enabled, and the cost of certain commands. @@ -687,6 +687,8 @@ See also: @create if given one; lists the option-types if not. /set -- Director only, changes parameters from the mush. See help @config parameters for available ones. + /save -- Like /set, but also modifies the config file so the + change persists over reboots. God only. & @conformat @conformat [=] @@ -814,7 +816,7 @@ See also: give, MONEY, @pay, money() See also: ATTRIBUTES, NON-STANDARD ATTRIBUTES & @create - @create [=] + @create [=[,]] Creates a thing with the specified name. Creating a thing costs a certain amount of MUSH money, which usually defaults to 10 pennies. @@ -824,6 +826,10 @@ See also: ATTRIBUTES, NON-STANDARD ATTRIBUTES Once you have created a thing, you can use it as a PUPPET, to store USER-DEFINED COMMANDS, or just as a prop. Some MUSHes choose to limit the number of objects that players can create by setting a QUOTA. + + Wizards can also specify the dbref of a garbage object to use when + creating the object. Otherwise, the object is given the next + available dbref. See also: give, @quota, MONEY & @dbck @@ -2602,7 +2608,7 @@ See also: give See also: give & @pcreate - @pcreate = + @pcreate = [, ] This Director-only command creates a player with the given name and password. diff --git a/game/txt/hlp/cobra_func.hlp b/game/txt/hlp/cobra_func.hlp index 823677e..9e44790 100644 --- a/game/txt/hlp/cobra_func.hlp +++ b/game/txt/hlp/cobra_func.hlp @@ -3591,6 +3591,7 @@ See also: anonymous attributes, sorting, sortby() d Sorts dbrefs. n Sorts integer numbers. f Sorts decimal numbers. + m Sorts strings with embedded numbers and dbrefs (as names). name Sorts dbrefs by their names. (Maybe case-sensitive) namei Sorts dbrefs by their names. (Always case-insensitive) conn Sorts dbrefs by their connection time. diff --git a/hdrs/access.h b/hdrs/access.h index 1409c7e..89524eb 100644 --- a/hdrs/access.h +++ b/hdrs/access.h @@ -57,6 +57,6 @@ bool add_access_sitelock(dbref player, const char *host, dbref who, int remove_access_sitelock(const char *pattern); void do_list_access(dbref player); int parse_access_options - (const char *opts, dbref *who, uint32_t * can, uint32_t * cant, dbref player); + (const char *opts, dbref *who, uint32_t *can, uint32_t *cant, dbref player); #endif /* __ACCESS_H */ diff --git a/hdrs/attrib.h b/hdrs/attrib.h index 3e4c30f..6354ca2 100644 --- a/hdrs/attrib.h +++ b/hdrs/attrib.h @@ -81,7 +81,7 @@ extern void atr_free_all(dbref thing); extern void atr_cpy(dbref dest, dbref source); extern char const *convert_atr(int oldatr); extern int atr_comm_match(dbref thing, dbref player, int type, int end, - char const *str, int just_match, char *atrname, + char const *str, int just_match, int check_locks, char *atrname, char **abp, dbref *errobj); extern int atr_comm_divmatch(dbref thing, dbref player, int type, int end, char const *str, int just_match, char *atrname, diff --git a/hdrs/boolexp.h b/hdrs/boolexp.h index e0ec958..d5ff2ee 100644 --- a/hdrs/boolexp.h +++ b/hdrs/boolexp.h @@ -2,6 +2,7 @@ #define BOOLEXP_H #include "copyrite.h" #include "chunk.h" +#include "dbio.h" typedef chunk_reference_t boolexp; @@ -24,8 +25,8 @@ extern boolexp parse_boolexp(dbref player, const char *buf, lock_type ltype); extern boolexp parse_boolexp_d(dbref player, const char *buf, lock_type ltype, int derefs); extern void free_boolexp(boolexp b); -boolexp getboolexp(FILE * f, const char *ltype); -void putboolexp(FILE * f, boolexp b); +boolexp getboolexp(PENNFILE *f, const char *ltype); +void putboolexp(PENNFILE *f, boolexp b); enum u_b_f { UB_ALL, /**< Use names of objects */ UB_DBREF, /**< Use dbrefs */ diff --git a/hdrs/conf.h b/hdrs/conf.h index 88d5414..eda877c 100644 --- a/hdrs/conf.h +++ b/hdrs/conf.h @@ -274,8 +274,8 @@ struct options_table { int player_name_len; /**< Maximum length of player names */ int queue_entry_cpu_time; /**< Maximum cpu time allowed per queue entry */ int ascii_names; /**< Are object names restricted to ascii characters? */ - int max_global_fns; /**< Maximum number of functions */ char chunk_swap_file[256]; /**< Name of the attribute swap file */ + int chunk_swap_initial; /**< Disc space to reserve for the swap file, in kibibytes */ int chunk_cache_memory; /**< Memory to use for the attribute cache */ int chunk_migrate_amount; /**< Number of attrs to migrate each second */ int read_remote_desc; /**< Can players read DESCRIBE attribute remotely? */ @@ -451,7 +451,6 @@ int cf_time(const char *opt, const char *val, void *loc, int maxval, #define TINY_MATH (options.tiny_math) #define NEWLINE_ONE_CHAR (options.newline_one_char) #define ONLY_ASCII_NAMES (options.ascii_names) -#define MAX_GLOBAL_FNS (options.max_global_fns) #define USE_QUOTA (options.use_quota) #define EMPTY_ATTRS (options.empty_attrs) #define FUNCTION_SIDE_EFFECTS (options.function_side_effects) diff --git a/hdrs/dbio.h b/hdrs/dbio.h index d1ec24b..c1d3356 100644 --- a/hdrs/dbio.h +++ b/hdrs/dbio.h @@ -9,44 +9,67 @@ #include #include +#ifdef HAVE_ZLIB_H +#include +#endif #ifdef HAVE_STDINT_H #include #endif extern jmp_buf db_err; -/** Run a function, and jump if error */ -#define OUTPUT(fun) do { if ((fun) < 0) longjmp(db_err, 1); } while (0) +typedef struct pennfile { + enum { PFT_FILE, PFT_PIPE, PFT_GZFILE } type; + union { + FILE *f; +#ifdef HAVE_LIBZ + gzFile g; +#endif + } handle; +} PENNFILE; + +PENNFILE *penn_fopen(const char *, const char *); +void penn_fclose(PENNFILE *); +int penn_fgetc(PENNFILE *); +char *penn_fgets(char *, int, PENNFILE *); +int penn_fputc(int, PENNFILE *); +int penn_fputs(const char *, PENNFILE *); +int penn_fprintf(PENNFILE *, const char *fmt, ...) + __attribute__ ((__format__(__printf__, 2, 3))); +int penn_ungetc(int, PENNFILE *); + +int penn_feof(PENNFILE *); + /* Output */ -extern void putref(FILE * f, long int ref); -extern void putstring(FILE * f, const char *s); -extern void db_write_labeled_string(FILE * f, char const *label, char const *value); -extern void db_write_labeled_int(FILE * f, char const *label, int value); -extern void db_write_labeld_uint32(FILE *, char const *, uint32_t); -extern void db_write_labeled_dbref(FILE * f, char const *label, dbref value); +extern void putref(PENNFILE *f, long int ref); +extern void putstring(PENNFILE *f, const char *s); +extern void db_write_labeled_string(PENNFILE *f, char const *label, char const *value); +extern void db_write_labeled_int(PENNFILE *f, char const *label, int value); +extern void db_write_labeld_uint32(PENNFILE *, char const *, uint32_t); +extern void db_write_labeled_dbref(PENNFILE *f, char const *label, dbref value); -extern void db_write_flag_db(FILE *); +extern void db_write_flag_db(PENNFILE *); -extern dbref db_write(FILE * f, int flag); -extern int db_paranoid_write(FILE * f, int flag); +extern dbref db_write(PENNFILE * f, int flag); +extern int db_paranoid_write(PENNFILE * f, int flag); /* Input functions */ -extern char *getstring_noalloc(FILE * f); -extern long getref(FILE * f); -extern void db_read_this_labeled_string(FILE * f, const char *label, char **val); -extern void db_read_labeled_string(FILE * f, char **label, char **val); -extern void db_read_this_labeled_int(FILE * f, const char *label, int *val); -extern void db_read_this_labeled_uint32(FILE * f, const char *lable, uint32_t * val); -extern void db_read_labeled_int(FILE * f, char **label, int *val); -extern void db_read_labeled_uint32(FILE * f, char **label, uint32_t * val); -extern void db_read_this_labeled_dbref(FILE * f, const char *label, dbref *val); -extern void db_read_labeled_dbref(FILE * f, char **label, dbref *val); -extern int load_flag_db(FILE *); +extern char *getstring_noalloc(PENNFILE * f); +extern long getref(PENNFILE * f); +extern void db_read_this_labeled_string(PENNFILE * f, const char *label, char **val); +extern void db_read_labeled_string(PENNFILE * f, char **label, char **val); +extern void db_read_this_labeled_int(PENNFILE * f, const char *label, int *val); +extern void db_read_this_labeled_uint32(PENNFILE * f, const char *lable, uint32_t * val); +extern void db_read_labeled_int(PENNFILE * f, char **label, int *val); +extern void db_read_labeled_uint32(PENNFILE * f, char **label, uint32_t * val); +extern void db_read_this_labeled_dbref(PENNFILE * f, const char *label, dbref *val); +extern void db_read_labeled_dbref(PENNFILE * f, char **label, dbref *val); +extern int load_flag_db(PENNFILE *); extern void init_postconvert(); -extern dbref db_read(FILE * f); +extern dbref db_read(PENNFILE * f); #endif diff --git a/hdrs/division.h b/hdrs/division.h index cce2ed8..e9e99ad 100644 --- a/hdrs/division.h +++ b/hdrs/division.h @@ -304,8 +304,8 @@ extern void init_powers(); extern div_pbits new_power_bitmask(); extern char power_is_zero(div_pbits pbits, int bytes); extern void do_power_cmd(dbref, const char *, const char *, const char *); -extern void powers_read_all(FILE *); -extern void power_write_all(FILE *); +extern void powers_read_all(PENNFILE *); +extern void power_write_all(PENNFILE *); extern POWER *has_power(dbref object, const char *name); extern div_pbits convert_old_cobra_powers(unsigned char *dp_bytes); extern char *powergroups_list(dbref, char); diff --git a/hdrs/externs.h b/hdrs/externs.h index 7f8efdf..08ff6f2 100644 --- a/hdrs/externs.h +++ b/hdrs/externs.h @@ -294,7 +294,7 @@ extern const char *get_namedreg(HASHTAB *, const char *); /* From create.c */ extern dbref do_dig(dbref player, const char *name, char **argv, int tport); -extern dbref do_create(dbref player, char *name, int cost); +extern dbref do_create(dbref player, char *name, int cost, char *newdbref); extern dbref do_real_open(dbref player, const char *direction, const char *linkto, dbref pseudo); extern void do_open(dbref player, const char *direction, char **links); @@ -362,7 +362,7 @@ dbref lookup_player(const char *name); dbref lookup_player_name(const char *name); /* from player.c */ dbref create_player(const char *name, const char *password, - const char *host, const char *ip); + const char *host, const char *ip, dbref try_dbref); dbref connect_player(const char *name, const char *password, const char *host, const char *ip, char *errbuf); void check_last(dbref player, const char *host, const char *ip); @@ -490,7 +490,11 @@ extern char *strlower(const char *s); extern char *strinitial(const char *s); extern char *upcasestr(char *s); extern char *skip_space(const char *s); +#ifdef HAVE_STRCHRNUL +#define seek_char(s,c) strchrnul((s),(c)) +#else extern char *seek_char(const char *s, char c); +#endif extern size_t u_strlen(const unsigned char *s); extern unsigned char *u_strncpy (unsigned char *restrict target, const unsigned char *restrict source, @@ -632,7 +636,7 @@ strdup(const char *s) __attribute_malloc__; #define mush_free(ptr,tag) mush_free_where((ptr), (tag), __FILE__, __LINE__) void mush_free_where(void *restrict ptr, const char *restrict check, const char *restrict filename, int line); - long get_random_long(long low, long high); + uint32_t get_random32(uint32_t low, uint32_t high); char *fullalias(dbref it); char *shortalias(dbref it); char *shortname(dbref it); @@ -718,6 +722,7 @@ strdup(const char *s) __attribute_malloc__; /* From destroy.c */ void do_undestroy(dbref player, char *name); dbref free_get(void); + int make_first_free(dbref object); void fix_free_list(void); void purge(void); void do_purge(dbref player); diff --git a/hdrs/extmail.h b/hdrs/extmail.h index 6a2ca86..2903d6d 100644 --- a/hdrs/extmail.h +++ b/hdrs/extmail.h @@ -74,8 +74,8 @@ extern void set_player_folder(dbref player, int fnum); extern void add_folder_name(dbref player, int fld, const char *name); extern struct mail *find_exact_starting_point(dbref player); extern void check_mail(dbref player, int folder, int silent); -extern int dump_mail(FILE * fp); -extern int load_mail(FILE * fp); +extern int dump_mail(PENNFILE * fp); +extern int load_mail(PENNFILE * fp); extern void mail_init(void); extern int mdb_top; extern void do_mail(dbref player, char *arg1, char *arg2); diff --git a/hdrs/flags.h b/hdrs/flags.h index 601ae56..85a09ad 100644 --- a/hdrs/flags.h +++ b/hdrs/flags.h @@ -8,6 +8,7 @@ #include "mushtype.h" #include "ptab.h" +#include "dbio.h" #include "division.h" typedef struct flag_info FLAG; @@ -78,8 +79,8 @@ extern int has_any_bits(const char *ns, object_flag_type source, object_flag_typ extern object_flag_type string_to_bits(const char *ns, const char *str); extern const char *bits_to_string(const char *ns, object_flag_type bitmask, dbref privs, dbref thing); -extern void flag_write_all(FILE *, const char *); -extern void flag_read_all(FILE *, const char *); +extern void flag_write_all(PENNFILE *, const char *); +extern void flag_read_all(PENNFILE *, const char *); extern int type_from_old_flags(long old_flags); extern object_flag_type flags_from_old_flags(long old_flags, long old_toggles, int type); diff --git a/hdrs/function.h b/hdrs/function.h index 556039a..8c4a474 100644 --- a/hdrs/function.h +++ b/hdrs/function.h @@ -48,15 +48,18 @@ typedef struct fun FUN; typedef void (*function_func) (FUN *, char *, char **, int, char *[], int[], dbref, dbref, dbref, const char *, PE_Info *); +typedef struct userfn_entry USERFN_ENTRY; + /** A calling pointer to a function. * This union holds either a pointer to a function's code or * the offset of the function in the user-defined function table. */ union fun_call { function_func fun; /**< Pointer to compiled function code */ - size_t offset; /**< Offset into user-defined function table */ + USERFN_ENTRY *ufun; /**< Pointer to @function location */ }; + /** A function. * This structure represents a mushcode function. */ @@ -75,20 +78,15 @@ struct fun { boolexp lock; /* Usability lock */ }; -typedef struct userfn_entry USERFN_ENTRY; /** A user-defined function * This structure represents an entry in the user-defined function table. */ struct userfn_entry { - char *fn; /**< Name of the function */ dbref thing; /**< Dbref of object where the function is defined */ char *name; /**< Name of attribute where the function is defined */ - unsigned int flags; /**< Bitflags of function */ }; -extern USERFN_ENTRY *userfn_tab; - void do_userfn(char *buff, char **bp, dbref obj, ATTR *attrib, int nargs, char **args, diff --git a/hdrs/game.h b/hdrs/game.h index 65856af..b153960 100644 --- a/hdrs/game.h +++ b/hdrs/game.h @@ -52,7 +52,7 @@ extern void do_hook_list(dbref player, char *command); /* From compress.c */ #if (COMPRESSION_TYPE > 0) -extern int init_compress(FILE * f); +int init_compress(PENNFILE *f); #endif /* From conf.c */ @@ -158,9 +158,10 @@ extern void do_enable(dbref player, const char *param, int state); extern void do_kick(dbref player, const char *num); extern void do_search(dbref player, const char *arg1, char **arg3); extern dbref do_pcreate - (dbref creator, const char *player_name, const char *player_password); -extern void do_quota - (dbref player, const char *arg1, const char *arg2, int set_q); + (dbref creator, const char *player_name, const char *player_password, + const char *try_dbref); +extern void do_quota(dbref player, const char *arg1, const char *arg2, + int set_q); extern void do_allquota(dbref player, const char *arg1, int quiet); extern void do_teleport (dbref player, const char *arg1, const char *arg2, int silent, int inside); @@ -181,7 +182,7 @@ extern void do_sitelock extern void do_sitelock_name(dbref player, const char *name); extern void do_chownall (dbref player, const char *name, const char *target, int preserve); -extern void NORETURN do_reboot(dbref player, int flag); +extern void do_reboot(dbref player, int flag); /* From destroy.c */ extern void do_dbck(dbref player); diff --git a/hdrs/malias.h b/hdrs/malias.h index 8cee083..2eb7136 100644 --- a/hdrs/malias.h +++ b/hdrs/malias.h @@ -42,8 +42,8 @@ extern void do_malias_stats(dbref player); extern void do_malias_nuke(dbref player); extern void do_malias_add(dbref player, char *alias, char *tolist); extern void do_malias_remove(dbref player, char *alias, char *tolist); -extern void load_malias(FILE * fp); -extern void save_malias(FILE * fp); +void load_malias(PENNFILE *fp); +void save_malias(PENNFILE *fp); extern void malias_cleanup(dbref player); extern void do_malias_set(dbref player, char *alias, char *tolist); #else /* MAIL_ALIASES */ diff --git a/hdrs/shs.h b/hdrs/shs.h index 3f9d744..ee5554a 100644 --- a/hdrs/shs.h +++ b/hdrs/shs.h @@ -1,8 +1,7 @@ #ifndef _SHS_H #define _SHS_H -#include "config.h" -#ifdef HAVE_STDINT +#ifdef HAVE_STDINT_H #include #endif @@ -12,17 +11,8 @@ #define LONG SHS_LONG #endif -#ifdef __MINGW32__ -typedef unsigned char BYTE; -typedef long LONG; -#else -typedef unsigned char BYTE; -#ifdef HAS_UINT32_T -typedef uint32_t LONG; -#else -typedef unsigned int LONG; -#endif -#endif +typedef uint8_t BYTE; +typedef uint32_t LONG; /* Ick. */ #define SHS_BLOCKSIZE 64 diff --git a/src/Makefile.in b/src/Makefile.in index 25d9af6..a545048 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -25,7 +25,8 @@ C_FILES=access.c atr_tab.c attrib.c boolexp.c bsd.c bufferq.c chunk.c \ plyrlist.c predicat.c privtab.c prog.c info_master.c ptab.c rob.c \ services.c set.c shs.c sig.c sort.c speech.c sql.c strdup.c \ strtree.c strutil.c tables.c timer.c unparse.c utils.c \ - version.c wait.c warnings.c wild.c wiz.c + version.c wait.c warnings.c wild.c wiz.c \ + SFMT.c # .o versions of above - these are used in the build @@ -41,7 +42,8 @@ O_FILES=bsd.o access.o atr_tab.o attrib.o boolexp.o bufferq.o chunk.o \ plyrlist.o prog.o info_master.o predicat.o privtab.o ptab.o rob.o \ services.o set.o shs.o sig.o sort.o speech.o sql.o strdup.o \ strtree.o strutil.o tables.o timer.o unparse.o utils.o \ - version.o wait.o warnings.o wild.o wiz.o + version.o wait.o warnings.o wild.o wiz.o \ + SFMT.o # This is a dummy target, in case you type 'make' in the source # directory (likely for emacs users who M-x compile.) @@ -118,27 +120,26 @@ indent: -T accent_info -T acsflag -T aig_func -T ALIST -T ansi_data \ -T ansi_string -T atr_err -T ATRALIAS -T ATTR -T BOOL -T boolexp \ -T boolexp_type -T BQUE -T branch_chain -T BUFFERQ -T bvm_opcode \ - -T BYTE -T CDESC -T CHAN -T CHANLIST -T CHANUSER \ - -T chunk_reference_t -T CNode -T COMLIST -T command_func \ - -T COMMAND_INFO -T comp_func -T compile_data -T COMSORTSTRUC \ - -T config_func -T CType -T dbref -T Debug_Info -T DESC \ - -T dfa_match_data -T eptrblock -T EVAL_CONTEXT -T FBLOCK \ - -T fd_type -T FLAG -T FLAG_ALIAS -T FLAGSPACE -T folder_array \ - -T FUN -T function_func -T FUNTAB -T GLOBALTAB -T hash_func \ - -T HASHENT -T HASHTAB -T heapframe -T help_file -T help_indx \ - -T ident_t -T im_key -T imaxdiv_t -T intmap -T IVAL \ - -T list_type_list -T lock_list -T lock_type -T LOCKMSGINFO \ - -T LONG -T ltype -T MAIL -T mail_flag -T makerecord \ - -T markup_information -T match_data -T MATH -T MEM -T na_lookup \ - -T NVAL -T object_flag_type -T OPTTAB -T patricia \ + -T BYTE -T CHAN -T CHANLIST -T CHANUSER -T chunk_reference_t \ + -T CNode -T COMLIST -T command_func -T COMMAND_INFO -T comp_func \ + -T compile_data -T COMSORTSTRUC -T config_func -T CType -T dbref \ + -T Debug_Info -T DESC -T dfa_match_data -T eptrblock \ + -T EVAL_CONTEXT -T FBLOCK -T fd_type -T FLAG -T FLAG_ALIAS \ + -T FLAGSPACE -T folder_array -T FUN -T function_func -T FUNTAB \ + -T GLOBALTAB -T hash_func -T HASHENT -T HASHTAB -T heapframe \ + -T help_file -T help_indx -T ident_t -T im_key -T imaxdiv_t \ + -T intmap -T IVAL -T list_type_list -T lock_list -T lock_type \ + -T LOCKMSGINFO -T LONG -T ltype -T MAIL -T mail_flag \ + -T makerecord -T markup_information -T match_data -T MATH -T MEM \ + -T na_lookup -T NVAL -T object_flag_type -T OPTTAB -T patricia \ -T pcre_study_data -T pcre_uint16 -T pcre_uint32 -T PE_Info \ - -T PENNCONF -T PENNCONFGROUP -T Port_t -T PRIV -T privbits \ - -T PTAB -T ptab_entry -T qsort_func -T real_pcre \ + -T PENNCONF -T PENNCONFGROUP -T PENNFILE -T Port_t -T PRIV \ + -T privbits -T PTAB -T ptab_entry -T qsort_func -T real_pcre \ -T recursion_info -T Region -T RegionHeader -T s_rec -T SHS_INFO \ -T slab -T sqlplatform -T STFunc -T StrNode -T StrTree \ -T switch_mask -T SWITCH_VALUE -T tcheck -T tlist \ - -T ucp_type_table -T UIVAL -T uschar -T UsedAttr -T USERFN_ENTRY \ - -T WAIT_TYPE -T warn_type -T Word \ + -T ucp_type_table -T uint32_t -T uint64_t -T UIVAL -T uschar \ + -T UsedAttr -T USERFN_ENTRY -T w128_t -T WAIT_TYPE -T warn_type \ $$file ; done) clean: diff --git a/src/SWITCHES b/src/SWITCHES index 63214d2..8afca23 100644 --- a/src/SWITCHES +++ b/src/SWITCHES @@ -81,6 +81,7 @@ MAX ME MEMBERS MOD +MOGRIFIER MORTAL MOTD MUTE @@ -130,6 +131,7 @@ RETROACTIVE ROOM ROOMS RSARGS +SAVE SEE SEEFLAG SELF diff --git a/src/access.c b/src/access.c index 7310bf5..148baa9 100644 --- a/src/access.c +++ b/src/access.c @@ -121,7 +121,7 @@ extern const unsigned char *tables; static void sitelock_free(struct access *ap) { - mush_free(ap->host, "sitelock.rule.host"); + mush_free(ap->host, "sitelock.rule.pattern"); if (ap->comment) mush_free(ap->comment, "sitelock.rule.comment"); if (ap->re) @@ -151,7 +151,7 @@ sitelock_alloc(const char *host, dbref who, tmp->who = who; tmp->can = can; tmp->cant = cant; - tmp->host = mush_strdup(host, "sitelock.rule.host"); + tmp->host = mush_strdup(host, "sitelock.rule.pattern"); if (comment && *comment) tmp->comment = mush_strdup(comment, "sitelock.rule.comment"); else @@ -381,10 +381,10 @@ site_can_access(const char *hname, uint32_t flag, dbref who) if (ap->can & ACS_SITELOCK) continue; if ((ap->can & ACS_REGEXP) - ? (qcomp_regexp_match(ap->re, hname) - || (p && qcomp_regexp_match(ap->re, p))) - : (quick_wild(ap->host, hname) - || (p && quick_wild(ap->host, p))) + ? (qcomp_regexp_match(ap->re, hname) + || (p && qcomp_regexp_match(ap->re, p))) + : (quick_wild(ap->host, hname) + || (p && quick_wild(ap->host, p))) && (ap->who == AMBIGUOUS || ap->who == who)) { /* Got one */ if (flag & ACS_CONNECT) { @@ -442,10 +442,10 @@ site_check_access(const char *hname, dbref who, int *rulenum) if (ap->can & ACS_SITELOCK) continue; if (((ap->can & ACS_REGEXP) - ? (qcomp_regexp_match(ap->re, hname) - || (p && qcomp_regexp_match(ap->re, p))) - : (quick_wild(ap->host, hname) - || (p && quick_wild(ap->host, p)))) + ? (qcomp_regexp_match(ap->re, hname) + || (p && qcomp_regexp_match(ap->re, p))) + : (quick_wild(ap->host, hname) + || (p && quick_wild(ap->host, p)))) && (ap->who == AMBIGUOUS || ap->who == who)) { /* Got one */ return ap; @@ -691,8 +691,8 @@ do_list_access(dbref player) * This makes a copy of the options string, so it's not modified. */ int -parse_access_options(const char *opts, dbref *who, uint32_t * can, - uint32_t * cant, dbref player) +parse_access_options(const char *opts, dbref *who, uint32_t *can, + uint32_t *cant, dbref player) { char myopts[BUFFER_LEN]; char *p; diff --git a/src/attrib.c b/src/attrib.c index e2b3590..b459356 100644 --- a/src/attrib.c +++ b/src/attrib.c @@ -233,13 +233,69 @@ atr_sub_branch(ATTR * branch) /** Scan an attribute list for an attribute with the specified name. * This continues from whatever start point is passed in. - * \param atr the start of the list to search from - * \param name the attribute name to look for - * \return the matching attribute, or NULL + * + * Attributes are stored as sorted linked lists. This means that + * search is O(N) in the worst case. An unsuccessful search is usually + * better than that, because we don't have to look at every attribute + * unless you're looking for something greater than all the attributes + * on the object. There are a couple of possibilities I've been + * mulling over for... um... years... about ways to improve this. + * + * Option 1 is to change the data structure. I'd use a hybrid between + * a standard linked list and a skip list. Most objects have under 5 + * attributes on them. With this few, a linear linked list is + * fine. When more attribute are added, though, it would turn into a + * skip list, with all current attributes having a depth of 1, and + * further attributes having a randomly chosen depth with a cap of, + * say, 5 (I'll have to work out the math to find the optimum + * size). This will provide O(lg N) searches on objects with lots of + * attributes and yet not take up lots of extra memory on objects with + * only a few attributes -- a problem with using a tree structure. All + * the code for this is in my head; I just need to sit down and write + * it. + * + * Option 2 is to speed up the current lookup. There are a lot of + * string comparisions that we don't strictly need: All attributes + * with the same name use the same underlying storage from a string + * pool. You can look up an attribute name and then just compare + * pointers, saving a lot of calls to strcoll(). The string pool is + * implemented using a red-black tree, so it needs O(lg P) string + * comparisions + O(N) pointer equality comparisions (P is the number + * of unique attribute names in the pool, N the number of attributes + * on the object). Hmm. I'm not so sure that's much of an improvement + * after all... Let's try it out anyways and see what happens. Don't + * expect this to be permanent, though. + * + * \param atr the start of the list to search from \param name the + * attribute name to look for \return the matching attribute, or NULL */ static ATTR * find_atr_in_list(ATTR * atr, char const *name) { +#define ATR_PTR_CMP +#ifdef ATR_PTR_CMP + /* New way; pointer comparisions */ + const char *memoized; + + memoized = st_find(name, &atr_names); + if (!memoized) /* This attribute name doesn't exist on any object */ + return NULL; + + while (atr) { + if (AL_NAME(atr) == memoized) + return atr; +#if 0 + /* Unfortunately, this will break under many locales, since + attribute list sorting uses strcoll() and not strcmp(). */ + else if (*memoized < *AL_NAME(atr)) + return NULL; /* Can't be any of the remaining attributes */ +#endif + else + atr = AL_NEXT(atr); + } +#else + /* Old way; lots of string comparisions */ + int comp; while (atr) { @@ -250,6 +306,7 @@ find_atr_in_list(ATTR * atr, char const *name) return atr; atr = AL_NEXT(atr); } +#endif return NULL; } @@ -1171,7 +1228,7 @@ use_attr(UsedAttr ** prev, char const *name, uint32_t no_prog) */ int atr_comm_match(dbref thing, dbref player, int type, int end, - char const *str, int just_match, char *atrname, char **abp, + char const *str, int just_match, int check_locks, char *atrname, char **abp, dbref * errobj) { uint32_t flag_mask; @@ -1185,15 +1242,16 @@ atr_comm_match(dbref thing, dbref player, int type, int end, UsedAttr *used_list, **prev; ATTR *skip[ATTRIBUTE_NAME_LIMIT / 2]; int skipcount; - int lock_checked = 0; + int lock_checked = !check_locks; char match_space[BUFFER_LEN * 2]; ssize_t match_space_len = BUFFER_LEN * 2; dbref local_ooref; /* check for lots of easy ways out */ - if ((type != '$' && type != '^') || !GoodObject(thing) || Halted(thing) - || (type == '$' && NoCommand(thing))) + if (type != '$' && type != '^') return 0; + if (check_locks && (!GoodObject(thing) || Halted(thing) || (type == '$' && NoCommand(thing)))) + return 0; if (type == '$') { flag_mask = AF_COMMAND; diff --git a/src/bsd.c b/src/bsd.c index b643541..a2bb918 100644 --- a/src/bsd.c +++ b/src/bsd.c @@ -106,7 +106,6 @@ #include "dbdefs.h" #include "flags.h" #include "lock.h" -#include "help.h" #include "match.h" #include "ansi.h" #include "pueblo.h" @@ -1098,10 +1097,17 @@ shovechars(Port_t port __attribute__ ((__unused__)), WTERMSIG(dump_status)); flag_broadcast("ROYALTY WIZARD", 0, T("GAME: ERROR! Forking database save failed!")); - } else if (WIFEXITED(dump_status) && WEXITSTATUS(dump_status) == 0) { - time(&globals.last_dump_time); - if (DUMP_NOFORK_COMPLETE && *DUMP_NOFORK_COMPLETE) - flag_broadcast(0, 0, "%s", DUMP_NOFORK_COMPLETE); + } else if (WIFEXITED(dump_status)) { + if (WEXITSTATUS(dump_status) == 0) { + time(&globals.last_dump_time); + if (DUMP_NOFORK_COMPLETE && *DUMP_NOFORK_COMPLETE) + flag_broadcast(0, 0, "%s", DUMP_NOFORK_COMPLETE); + } else { + do_rawlog(LT_ERR, T("ERROR! forking dump exited with exit code %d"), + WEXITSTATUS(dump_status)); + flag_broadcast("ROYALTY WIZARD", 0, + T("GAME: ERROR! Forking database save failed!")); + } } dump_error = 0; dump_status = 0; @@ -2753,7 +2759,7 @@ check_connect(DESC *d, const char *msg) user, d->addr, d->descriptor); return 0; } - player = create_player(user, password, d->addr, d->ip); + player = create_player(user, password, d->addr, d->ip, NOTHING); if (player == NOTHING) { queue_string_eol(d, T(create_fail)); do_rawlog(LT_CONN, @@ -2867,6 +2873,7 @@ close_sockets(void) DESC *d, *dnext; const char *shutmsg; int shutlen; + ssize_t res; shutmsg = T(shutdown_message); shutlen = strlen(shutmsg); @@ -2882,7 +2889,8 @@ close_sockets(void) byebye[0].iov_len = shutlen; byebye[1].iov_base = (char *) "\r\n"; byebye[1].iov_len = 2; - writev(d->outdesc, byebye, 2); + /* FIXME: We're using res.. for the mere fact we get a warning otherwise.. */ + res = writev(d->outdesc, byebye, 2); #else if (d->outdesc == console_outpt) { write(d->outdesc, shutmsg, shutlen); @@ -3423,6 +3431,7 @@ announce_connect(dbref player, int isnew, int num) { dbref loc; char tbuf1[BUFFER_LEN]; + char *message; char *myenv[2]; dbref zone; dbref obj; @@ -3438,15 +3447,14 @@ announce_connect(dbref player, int isnew, int num) /* Redundant, but better for translators */ if (Dark(player)) { - snprintf(tbuf1, BUFFER_LEN, (num > 1) ? T("%s has DARK-reconnected.") : - T("%s has DARK-connected."), Name(player)); + message = (num > 1) ? T("has DARK-reconnected.") : T("has DARK-connected."); } else if (hidden(player)) { - snprintf(tbuf1, BUFFER_LEN, (num > 1) ? T("%s has HIDDEN-reconnected.") : - T("%s has HIDDEN-connected."), Name(player)); + message = (num > 1) ? T("has HIDDEN-reconnected.") : + T("has HIDDEN-connected."); } else { - snprintf(tbuf1, BUFFER_LEN, (num > 1) ? T("%s has reconnected.") : - T("%s has connected."), Name(player)); + message = (num > 1) ? T("has reconnected.") : T("has connected."); } + snprintf(tbuf1, BUFFER_LEN, "%s %s", Name(player), message); /* send out messages */ if (!Dark(player)) @@ -3454,7 +3462,7 @@ announce_connect(dbref player, int isnew, int num) #ifdef CHAT_SYSTEM if (ANNOUNCE_CONNECTS) - chat_player_announce(player, tbuf1, (num == 1)); + chat_player_announce(player, message, (num == 1)); #endif /* CHAT_SYSTEM */ loc = Location(player); @@ -3533,6 +3541,8 @@ announce_connect(dbref player, int isnew, int num) strcpy(global_eval_context.ccom, ""); } +/* TODO: Compare to present day PennMUSH announce_disconnect.. We do things differently, though I think we should match up with the basic method + * */ void announce_disconnect(dbref player) { @@ -3540,6 +3550,7 @@ announce_disconnect(dbref player) int num; DESC *d; char tbuf1[BUFFER_LEN]; + /* TODO: See above, char *message; */ dbref zone, obj; int j; struct module_entry_t *m; @@ -4771,7 +4782,7 @@ close_ssl_connections(void) void dump_reboot_db(void) { - FILE *f; + PENNFILE *f; DESC *d; SU_PATH *exit_path; long flags = RDBF_SCREENSIZE | RDBF_TTYPE | RDBF_PUEBLO_CHECKSUM @@ -4781,14 +4792,14 @@ dump_reboot_db(void) exit(0); } else { - f = fopen(REBOOTFILE, "w"); + f = penn_fopen(REBOOTFILE, "w"); /* This shouldn't happen */ if (!f) { flag_broadcast(0, 0, T("GAME: Error writing reboot database!")); exit(0); } /* Write out the reboot db flags here */ - fprintf(f, "V%ld\n", flags); + penn_fprintf(f, "V%ld\n", flags); putref(f, sock); putref(f, maxd); /* First, iterate through all descriptors to get to the end @@ -4835,7 +4846,7 @@ dump_reboot_db(void) putstring(f, poll_msg); putref(f, globals.first_start_time); putref(f, globals.reboot_count); - fclose(f); + penn_fclose(f); } } @@ -4844,7 +4855,7 @@ dump_reboot_db(void) void load_reboot_db(void) { - FILE *f; + PENNFILE *f; DESC *d = NULL; DESC *closed = NULL, *nextclosed; int val; @@ -4855,7 +4866,7 @@ load_reboot_db(void) char tbuf1[BUFFER_LEN]; SU_PATH *epnext, *epprev; dbref exit_path; - f = fopen(REBOOTFILE, "r"); + f = penn_fopen(REBOOTFILE, "r"); if (!f) { restarting = 0; return; @@ -4866,11 +4877,11 @@ load_reboot_db(void) * If not, assume we're using the original format, in which the * sock appears first * */ - c = getc(f); /* Skip the V */ + c = penn_fgetc(f); /* Skip the V */ if (c == 'V') { flags = getref(f); } else { - ungetc(c, f); + penn_ungetc(c, f); } sock = getref(f); @@ -5017,7 +5028,7 @@ load_reboot_db(void) } #endif - fclose(f); + penn_fclose(f); remove(REBOOTFILE); flag_broadcast(0, 0, T("GAME: Reboot finished.")); } @@ -5394,6 +5405,19 @@ do_reboot(dbref player, int flag) struct module_entry_t *m; void (*handle)(); +#ifndef WIN32 + /* Quick and dirty check to make sure the executable is still + there. Not a security check to speak of, hence the race condition + implied by using access() doesn't matter. The exec can still fail + for various reasons, but if it does, it gets logged and you get an + inadvertent full @shutdown. */ + if (access(saved_argv[0], R_OK | X_OK) < 0) { + notify_format(player, T("Unable to reboot using executable '%s': %s"), + saved_argv[0], strerror(errno)); + return; + } +#endif + if (player == NOTHING) { flag_broadcast(0, 0, T @@ -5453,7 +5477,10 @@ do_reboot(dbref player, int flag) #else execl("cobramush.exe", "cobramush.exe", "/run", NULL); #endif /* WIN32 */ - exit(1); /* Shouldn't ever get here, but just in case... */ + /* Shouldn't ever get here, but just in case... */ + fprintf(stderr, "Unable to restart game: exec: %s\nAborting.", + strerror(errno)); + exit(1); } /* File modification watching code. Linux-specific for now. diff --git a/src/chunk.c b/src/chunk.c index 304db95..1098f29 100644 --- a/src/chunk.c +++ b/src/chunk.c @@ -214,6 +214,8 @@ #include #include #include + +#define _XOPEN_SOURCE 600 #include #include #include @@ -222,11 +224,14 @@ #include #include #else -#define _XOPEN_SOURCE 500 #define __USE_UNIX98 #include #endif #include +#ifdef I_SYS_STAT +#include +#endif + #include "externs.h" #include "boolexp.h" @@ -2353,6 +2358,12 @@ chunk_init(void) cache_head = NULL; cache_tail = NULL; +#ifdef HAVE_POSIX_FALLOCATE + /* Reserve some space for the swap file to start with. */ + if (options.chunk_swap_initial > 0) + posix_fallocate(swap_fd, 0, (options.chunk_swap_initial * 1024)); +#endif + region_count = 0; region_array_len = FIXME_INIT_REGION_LEN; #ifdef DEBUG_CHUNK_MALLOC @@ -2484,6 +2495,19 @@ chunk_fork_file(void) j++; } +#ifdef HAVE_POSIX_FALLOCATE + /* Try to reserve all the space needed for the child's copy of the chunk file all at once. */ + { + struct stat fsize; + if (fstat(swap_fd, &fsize) == 0) + posix_fallocate(swap_fd_child, 0, fsize.st_size); + } +#endif + +#ifdef HAVE_POSIX_FADVISE + posix_fadvise(swap_fd, 0, 0, POSIX_FADV_SEQUENTIAL); +#endif + rhp = find_available_cache_region(); prev = rhp->prev; next = rhp->next; @@ -2498,6 +2522,10 @@ chunk_fork_file(void) rhp->prev = prev; rhp->next = next; +#ifdef HAVE_POSIX_FADVISE + posix_fadvise(swap_fd, 0, 0, POSIX_FADV_RANDOM); +#endif + return 1; } @@ -2522,6 +2550,11 @@ chunk_fork_child(void) return; close(swap_fd); + +#ifdef HAVE_POSIX_FADVISE + posix_fadvise(swap_fd_child, 0, 0, POSIX_FADV_RANDOM); +#endif + swap_fd = swap_fd_child; swap_fd_child = -1; } diff --git a/src/cmds.c b/src/cmds.c index 253555f..c667661 100644 --- a/src/cmds.c +++ b/src/cmds.c @@ -192,11 +192,29 @@ COMMAND(cmd_config) notify(player, T("What did you want to set?")); return; } - if (!config_set(arg_left, arg_right, 1, 0) - && !config_set(arg_left, arg_right, 1, 1)) - notify(player, T("Couldn't set that option")); - else - notify(player, T("Option set.")); + { + 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 (!config_set(arg_left, arg_right, source, 0) + && !config_set(arg_left, arg_right, source, 1)) + notify(player, T("Couldn't set that option")); + else { + if (source == 2) { +#ifdef HAVE_ED + notify(player, T("Option set and saved.")); +#else + notify(player, T("Option set but not saved (Saves disabled.)")); +#endif + } else + notify(player, T("Option set.")); + } + } } else do_config_list(player, arg_left, lc); } @@ -208,7 +226,19 @@ COMMAND(cmd_cpattr) COMMAND(cmd_create) { - do_create(player, arg_left, parse_integer(arg_right)); + + int cost = 0; + char *newdbref; + + if (args_right[1] && *args_right[1]) + cost = parse_integer(args_right[1]); + + if (args_right[2] && *args_right[2]) + newdbref = args_right[2]; + else + newdbref = (char *) NULL; + + do_create(player, arg_left, cost, newdbref); } COMMAND(cmd_clone) @@ -802,7 +832,14 @@ COMMAND(cmd_password) COMMAND(cmd_pcreate) { - do_pcreate(player, arg_left, arg_right); + const char *newdbref; + + if (args_right[2] && *args_right[2]) + newdbref = args_right[2]; + else + newdbref = NULL; + + do_pcreate(player, arg_left, args_right[1], newdbref); } COMMAND(cmd_pemit) diff --git a/src/command.c b/src/command.c index d7c863a..7d203fc 100644 --- a/src/command.c +++ b/src/command.c @@ -114,7 +114,7 @@ COMLIST commands[] = { #endif CHAT_SYSTEM */ {"@CONFIG", - "SET LOWERCASE LIST GLOBALS DEFAULTS COSTS FLAGS POWERS FUNCTIONS COMMANDS ATTRIBS", + "SET SAVE LOWERCASE LIST GLOBALS DEFAULTS COSTS FLAGS POWERS FUNCTIONS COMMANDS ATTRIBS", cmd_config, CMD_T_ANY | CMD_T_EQSPLIT, NULL}, {"@CPATTR", "CONVERT NOFLAGCOPY", cmd_cpattr, CMD_T_ANY | CMD_T_EQSPLIT | CMD_T_RS_ARGS, @@ -2038,7 +2038,7 @@ run_hook_override(COMMAND_INFO *cmd, dbref player, const char *commandraw) cmd->hooks.override.attrname, commandraw); } else { return atr_comm_match(cmd->hooks.override.obj, player, '$', ':', commandraw, - 0, NULL, NULL, NULL); + 0, 1, NULL, NULL, NULL); } } diff --git a/src/comp_h.c b/src/comp_h.c index 72ea30f..d401d31 100644 --- a/src/comp_h.c +++ b/src/comp_h.c @@ -23,6 +23,7 @@ #include "externs.h" #include "mushdb.h" #include "mymalloc.h" +#include "dbio.h" #ifdef WIN32 #pragma warning( disable : 4244) /* NJG: disable warning re conversion */ #endif @@ -58,7 +59,7 @@ slab *huffman_slab = NULL; static int fix_tree_depth(CNode *node, int height, int zeros); static void add_ones(CNode *node); static void build_ctable(CNode *root, CType code, int numbits); -int init_compress(FILE * f); +int init_compress(PENNFILE *f); /** Huffman-compress a string. @@ -321,7 +322,7 @@ build_ctable(CNode *root, CType code, int numbits) * \param f filehandle to read from to build the tree. */ int -init_compress(FILE * f) +init_compress(PENNFILE *f) { int total; unsigned char c; @@ -361,8 +362,8 @@ init_compress(FILE * f) /* Part 2: count frequencies */ if (f) { total = 0; - while (!feof(f) && (!SAMPLE_SIZE || (total++ < SAMPLE_SIZE))) { - c = fgetc(f); + while (!penn_feof(f) && (!SAMPLE_SIZE || (total++ < SAMPLE_SIZE))) { + c = penn_fgetc(f); table[c].freq++; } } diff --git a/src/comp_w.c b/src/comp_w.c index d30835e..7692cf0 100644 --- a/src/comp_w.c +++ b/src/comp_w.c @@ -159,7 +159,7 @@ static long total_entries = 0; static unsigned char *b; static void output_previous_word(void); -int init_compress(FILE *f); +int init_compress(PENNFILE *f); #ifdef COMP_STATS void compress_stats(long *entries, long *mem_used, long *total_uncompressed, long *total_compressed); @@ -359,7 +359,7 @@ safe_uncompress(unsigned char const *s) * \param f (unused). */ int -init_compress(FILE *f __attribute__ ((__unused__))) +init_compress(PENNFILE *f __attribute__ ((__unused__))) { memset(words, 0, sizeof words); memset(words_len, 0, sizeof words_len); diff --git a/src/comp_w8.c b/src/comp_w8.c index 0657ee0..fb85c22 100644 --- a/src/comp_w8.c +++ b/src/comp_w8.c @@ -160,7 +160,7 @@ static long total_entries = 0; static unsigned char *b; static void output_previous_word(void); -int init_compress(FILE * f); +int init_compress(PENNFILE * f); #ifdef COMP_STATS void compress_stats(long *entries, long *mem_used, long *total_uncompressed, long *total_compressed); @@ -364,7 +364,7 @@ safe_uncompress(unsigned char const *s) * \param f (unused). */ int -init_compress(FILE * f __attribute__ ((__unused__))) +init_compress(PENNFILE * f __attribute__ ((__unused__))) { memset(words, 0, sizeof words); memset(words_len, 0, sizeof words_len); diff --git a/src/conf.c b/src/conf.c index 0028904..847e4e0 100644 --- a/src/conf.c +++ b/src/conf.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "conf.h" #include "externs.h" @@ -43,8 +44,7 @@ time_t mudtime; /**< game time, in seconds */ static void show_compile_options(dbref player); -static char *config_list_helper(dbref player, COBRA_CONF *cp, int lc); -static char *config_list_helper2(dbref player, COBRA_CONF *cp, int lc); +static char *config_to_string(dbref player, COBRA_CONF *cp, int lc); OPTTAB options; /**< The table of configuration options */ HASHTAB local_options; /**< Hash table for local config options */ @@ -343,8 +343,6 @@ COBRA_CONF conftable[] = { {"queue_entry_cpu_time", cf_int, &options.queue_entry_cpu_time, 100000, 0, "limits"} , - {"max_global_fns", cf_int, &options.max_global_fns, 2000, 0, 0} - , {"use_quota", cf_bool, &options.use_quota, 2, 0, "limits"} , {"max_channels", cf_int, &options.max_channels, 1000, 0, "chat"} @@ -484,6 +482,9 @@ COBRA_CONF conftable[] = { {"chunk_swap_file", cf_str, options.chunk_swap_file, sizeof options.chunk_swap_file, 0, "files"} , + {"chunk_swap_initial_size", cf_int, &options.chunk_swap_initial, 1000000, 0, + "files"} + , {"chunk_cache_memory", cf_int, &options.chunk_cache_memory, 1000000000, 65510 * 2, "files"} , @@ -865,6 +866,46 @@ validate_config(void) #undef VALIDATE } +static char *toplevel_cfile = NULL; + +static void +append_restriction(const char *r, const char *what, const char *opts) +{ + FILE *out; + + out = fopen(toplevel_cfile, "a"); + if (out) { + fprintf(out, "# Added by @config/save\n%s %s %s\n\n", r, what, opts); + fclose(out); + } +} + +/* Not perfect -- things defined in included config files won't + get changed -- but it'll catch most cases. +*/ +static void +save_config_option(COBRA_CONF *cp) +{ +#if defined(HAVE_ED) + FILE *ed; + + /* ed is the standard! Why reinvent it? */ + + ed = popen(ED_PATH, "w"); + if (!ed) { + do_rawlog(LT_ERR, "Unable to open ed: %s", strerror(errno)); + return; + } + + fprintf(ed, "e %s\n", toplevel_cfile); + fprintf(ed, ",s/^[[:space:]]*%s[[:space:]].*$/%s/\n", cp->name, + trim_space_sep(config_to_string(GOD, cp, 1), ' ')); + fputs("wq\n", ed); + pclose(ed); +#endif + +} + /** Set a configuration option. * This function sets a runtime configuration option. During the load * of the configuration file, it gets run twice - once to set the @@ -872,7 +913,7 @@ validate_config(void) * that require having the flag table available. * \param opt name of the option. * \param val value to set the option to. - * \param source 0 if being set from mush.cnf, 1 from softcode. + * \param source 0 if being set from mush.cnf, 1 from softcode, 2 from softcode and saving. * \param restrictions 1 if we're setting restriction options, 0 for others. * \retval 1 success. * \retval 0 failure. @@ -927,6 +968,8 @@ config_set(const char *opt, char *val, int source, int restrictions) } return 0; } + if (source == 2) + append_restriction("restrict_command", val, p); return 1; } else if (!strcasecmp(opt, "restrict_function")) { if (!restrictions) @@ -950,6 +993,8 @@ config_set(const char *opt, char *val, int source, int restrictions) } return 0; } + if (source == 2) + append_restriction("restrict_function", val, p); return 1; } else if (!strcasecmp(opt, "reserve_alias")) { if (!restrictions) @@ -975,6 +1020,8 @@ config_set(const char *opt, char *val, int source, int restrictions) } return 0; } + if (source == 2) + append_restriction("reserve_alias", val, p); return 1; } else if (!strcasecmp(opt, "attribute_alias")) { if (!restrictions) @@ -995,6 +1042,8 @@ config_set(const char *opt, char *val, int source, int restrictions) } return 0; } + if (source == 2) + append_restriction("attribute_alias", val, p); return 1; } else if (!strcasecmp(opt, "function_alias")) { if (!restrictions) @@ -1015,6 +1064,8 @@ config_set(const char *opt, char *val, int source, int restrictions) } return 0; } + if (source == 2) + append_restriction("function_alias", val, p); return 1; } else if (!strcasecmp(opt, "help_command") || !strcasecmp(opt, "ahelp_command")) { @@ -1023,7 +1074,7 @@ config_set(const char *opt, char *val, int source, int restrictions) if (!restrictions) return 0; /* Add a new help-like command */ - if (source == 1) + if (source >= 1) /* Can't do this from @config/set */ return 0; if (!val || !*val) { do_rawlog(LT_ERR, @@ -1056,20 +1107,26 @@ config_set(const char *opt, char *val, int source, int restrictions) && strcmp(cp->group, "messages") != 0)) && !strcasecmp(cp->name, opt)) { i = cp->handler(opt, val, cp->loc, cp->max, source); - if (i) + if (i) { cp->overridden = 1; + if(source == 2) + save_config_option(cp); + } return i; } } - for (cp = (COBRA_CONF *) hash_firstentry(&local_options); cp; - cp = (COBRA_CONF *) hash_nextentry(&local_options)) { - int i = 0; + for (cp = hash_firstentry(&local_options); cp; + cp = hash_nextentry(&local_options)) { + int i = 0; if ((!source || (cp->group && strcmp(cp->group, "files") != 0 && strcmp(cp->group, "messages") != 0)) && !strcasecmp(cp->name, opt)) { i = cp->handler(opt, val, cp->loc, cp->max, source); - if (i) + if (i) { cp->overridden = 1; + if(source == 2) + save_config_option(cp); + } return i; } } @@ -1241,7 +1298,6 @@ conf_default_set(void) options.max_guest_pennies = 100000; options.max_depth = 10; options.max_parents = 10; - options.max_global_fns = 50; options.purge_interval = 601; options.dbck_interval = 599; options.max_attrcount = 2048; @@ -1252,6 +1308,7 @@ conf_default_set(void) options.ascii_names = 1; options.call_lim = 10000; strcpy(options.chunk_swap_file, "data/chunkswap"); + options.chunk_swap_initial = 2048; options.chunk_cache_memory = 1000000; options.chunk_migrate_amount = 50; options.read_remote_desc = 0; @@ -1302,8 +1359,8 @@ config_file_startup(const char *conf, int restrictions) COBRA_CONF *cp; char tbuf1[BUFFER_LEN]; char *p, *q, *s; - static char cfile[BUFFER_LEN]; /* Remember the last one */ + if (conf_recursion == 0) { if (conf && *conf) strcpy(cfile, conf); @@ -1313,6 +1370,8 @@ config_file_startup(const char *conf, int restrictions) return 0; } do_rawlog(LT_ERR, "Reading %s", cfile); + if (toplevel_cfile == NULL) + toplevel_cfile = mush_strdup(cfile, "config.file"); } else { if (conf && *conf) fp = fopen(conf, FOPEN_READ); @@ -1467,7 +1526,7 @@ do_config_list(dbref player, const char *type, int lc) /* It wasn't a group. Is is one or more specific options? */ for (cp = conftable; cp->name; cp++) { if (cp->group && string_prefix(cp->name, type)) { - notify(player, config_list_helper(player, cp, lc)); + notify(player, config_to_string(player, cp, lc)); found = 1; } } @@ -1476,7 +1535,7 @@ do_config_list(dbref player, const char *type, int lc) for (cp = (COBRA_CONF *) hash_firstentry(&local_options); cp; cp = (COBRA_CONF *) hash_nextentry(&local_options)) { if (cp->group && !strcasecmp(cp->name, type)) { - notify(player, config_list_helper(player, cp, lc)); + notify(player, config_to_string(player, cp, lc)); found = 1; } } @@ -1497,13 +1556,13 @@ do_config_list(dbref player, const char *type, int lc) else { for (cp = conftable; cp->name; cp++) { if (cp->group && !strcmp(cp->group, cgp->name)) { - notify(player, config_list_helper(player, cp, lc)); + notify(player, config_to_string(player, cp, lc)); } } for (cp = (COBRA_CONF *) hash_firstentry(&local_options); cp; cp = (COBRA_CONF *) hash_nextentry(&local_options)) { if (cp->group && !strcasecmp(cp->group, cgp->name)) { - notify(player, config_list_helper(player, cp, lc)); + notify(player, config_to_string(player, cp, lc)); } } } @@ -1524,7 +1583,9 @@ do_config_list(dbref player, const char *type, int lc) /** Lowercase a string if we've been asked to */ #define MAYBE_LC(x) (lc ? strlower(x) : x) static char * -config_list_helper(dbref player __attribute__ ((__unused__)), COBRA_CONF *cp, int lc) +config_to_string(dbref player + __attribute__ ((__unused__)), COBRA_CONF *cp, int lc + __attribute__ ((__unused__))) { static char result[BUFFER_LEN]; char *bp = result; @@ -1564,8 +1625,9 @@ config_list_helper(dbref player __attribute__ ((__unused__)), COBRA_CONF *cp, in /* This one doesn't return the names */ static char * -config_list_helper2(dbref player __attribute__ ((__unused__)), COBRA_CONF *cp, int lc - __attribute__ ((__unused__))) +config_to_string2(dbref player + __attribute__ ((__unused__)), COBRA_CONF *cp, int lc + __attribute__ ((__unused__))) { static char result[BUFFER_LEN]; char *bp = result; @@ -1609,14 +1671,14 @@ FUNCTION(fun_config) if (args[0] && *args[0]) { for (cp = conftable; cp->name; cp++) { if (cp->group && !strcasecmp(cp->name, args[0])) { - safe_str(config_list_helper2(executor, cp, 0), buff, bp); + safe_str(config_to_string2(executor, cp, 0), buff, bp); return; } } for (cp = (COBRA_CONF *) hash_firstentry(&local_options); cp; cp = (COBRA_CONF *) hash_nextentry(&local_options)) { if (cp->group && !strcasecmp(cp->name, args[0])) { - safe_str(config_list_helper2(executor, cp, 0), buff, bp); + safe_str(config_to_string2(executor, cp, 0), buff, bp); return; } } @@ -1755,6 +1817,22 @@ show_compile_options(dbref player) notify(player, T(" Changed help files will be automatically reindexed.")); #endif +#ifdef HAVE_SSE2 + notify(player, T(" SSE2 instructions are being used.")); +#endif + +#ifdef HAVE_SSE3 + notify(player, T(" SSE3 instructions are being used.")); +#endif + +#ifdef HAVE_ALTIVEC + notify(player, T(" Altivec instructions are being used.")); +#endif +#ifdef HAVE_ED + notify(player, T(" @config/save is enabled.")); +#else + notify(player, T(" @config/save is disabled.")); +#endif } diff --git a/src/cque.c b/src/cque.c index f15ab28..94ee972 100644 --- a/src/cque.c +++ b/src/cque.c @@ -72,8 +72,6 @@ typedef struct bque { HASHTAB namedregs; } BQUE; -slab *bque_slab = NULL; /**< slab for 'struct bque' allocations */ - intmap *queue_map = NULL; static uint32_t top_qid = 1; #define MAX_PID (1U << 15) @@ -117,8 +115,6 @@ extern sig_atomic_t cpu_time_limit_hit; /**< Have we used too much CPU? */ void init_queue(void) { - bque_slab = slab_create("command queues", sizeof(BQUE)); - slab_set_opt(bque_slab, SLAB_ALLOC_BEST_FIT, 1); queue_map = im_new(); } @@ -209,18 +205,18 @@ free_qentry(BQUE * point) int a; for (a = 0; a < 10; a++) if (point->env[a]) { - mush_free(point->env[a], "bqueue_env"); + mush_free(point->env[a], "cqueue.env"); } for (a = 0; a < NUMQ; a++) if (point->rval[a]) { - mush_free(point->rval[a], "bqueue_rval"); + mush_free(point->rval[a], "cqueue.rval"); } if (point->semattr) mush_free(point->semattr, "bqueue_semattr"); if (point->comm) - mush_free(point->comm, "bqueue_comm"); + mush_free(point->comm, "cqueue.comm"); im_delete(queue_map, point->qid); - slab_free(bque_slab, point); + mush_free(point, "cqueue"); } static int @@ -229,7 +225,7 @@ pay_queue(dbref player, const char *command) int estcost; estcost = QUEUE_COST + - (QUEUE_LOSS ? ((get_random_long(0, QUEUE_LOSS - 1) == 0) ? 1 : 0) : + (QUEUE_LOSS ? ((get_random32(0, QUEUE_LOSS - 1) == 0) ? 1 : 0) : 0); if (!quiet_payfor(player, estcost)) { notify(Owner(player), T("Not enough money to queue command.")); @@ -333,9 +329,9 @@ parse_que(dbref player, const char *command, dbref cause) notify(player, T("Queue entry table full. Try again later.")); return; } - tmp = (BQUE *) slab_malloc(bque_slab, NULL); + tmp = (BQUE *) mush_malloc(sizeof *tmp, "cqueue"); tmp->qid = qid; - tmp->comm = mush_strdup(command, "bqueue_comm"); + tmp->comm = mush_strdup(command, "cqueue.comm"); tmp->semattr = NULL; tmp->player = player; tmp->queued = QUEUE_PER_OWNER ? Owner(player) : player; @@ -348,14 +344,14 @@ parse_que(dbref player, const char *command, dbref cause) if (!global_eval_context.wnxt[a]) tmp->env[a] = NULL; else { - tmp->env[a] = mush_strdup(global_eval_context.wnxt[a], "bqueue_env"); + tmp->env[a] = mush_strdup(global_eval_context.wnxt[a], "cqueue.env"); } for (a = 0; a < NUMQ; a++) if (!global_eval_context.rnxt[a] || !global_eval_context.rnxt[a][0]) tmp->rval[a] = NULL; else { tmp->rval[a] = - mush_strdup(global_eval_context.rnxt[a], "bqueue_rval"); + mush_strdup(global_eval_context.rnxt[a], "cqueue.rval"); } init_namedregs(&tmp->namedregs); copy_namedregs(&tmp->namedregs, &global_eval_context.namedregs); @@ -386,9 +382,9 @@ div_parse_que(dbref division, const char *command, dbref called_division, return; if ((qid = create_qid()) == -1) /* No room to process shit.. don't do shit */ return; - tmp = (BQUE *) slab_malloc(bque_slab, NULL); + tmp = (BQUE *) mush_malloc(sizeof *tmp, "cqueue"); tmp->qid = qid; - tmp->comm = mush_strdup(command, "bqueue_comm"); + tmp->comm = mush_strdup(command, "cqueue.comm"); tmp->semattr = NULL; tmp->player = division; tmp->queued = QUEUE_PER_OWNER ? Owner(division) : division; @@ -402,14 +398,14 @@ div_parse_que(dbref division, const char *command, dbref called_division, if (!global_eval_context.wnxt[a]) tmp->env[a] = NULL; else { - tmp->env[a] = mush_strdup(global_eval_context.wnxt[a], "bqueue_env"); + tmp->env[a] = mush_strdup(global_eval_context.wnxt[a], "cqueue.env"); } for (a = 0; a < NUMQ; a++) if (!global_eval_context.rnxt[a] || !global_eval_context.rnxt[a][0]) tmp->rval[a] = NULL; else { tmp->rval[a] = - mush_strdup(global_eval_context.rnxt[a], "bqueue_rval"); + mush_strdup(global_eval_context.rnxt[a], "cqueue.rval"); } init_namedregs(&tmp->namedregs); copy_namedregs(&tmp->namedregs, &global_eval_context.namedregs); @@ -532,9 +528,9 @@ wait_que(dbref player, int waittill, char *command, dbref cause, dbref sem, return -1; if ((qid = create_qid()) == -1) /* can not obtain a QID */ return -1; - tmp = (BQUE *) slab_malloc(bque_slab, NULL); + tmp = (BQUE *) mush_malloc(sizeof *tmp, "cqueue"); tmp->qid = qid; - tmp->comm = mush_strdup(command, "bqueue_comm"); + tmp->comm = mush_strdup(command, "cqueue.comm"); tmp->player = player; tmp->queued = QUEUE_PER_OWNER ? Owner(player) : player; tmp->realcause = tmp->cause = cause; @@ -546,7 +542,7 @@ wait_que(dbref player, int waittill, char *command, dbref cause, dbref sem, if (!global_eval_context.wnxt[a]) tmp->env[a] = NULL; else { - tmp->env[a] = mush_strdup(global_eval_context.wnxt[a], "bqueue_env"); + tmp->env[a] = mush_strdup(global_eval_context.wnxt[a], "cqueue.env"); } } for (a = 0; a < NUMQ; a++) { @@ -554,7 +550,7 @@ wait_que(dbref player, int waittill, char *command, dbref cause, dbref sem, tmp->rval[a] = NULL; else { tmp->rval[a] = - mush_strdup(global_eval_context.rnxt[a], "bqueue_rval"); + mush_strdup(global_eval_context.rnxt[a], "cqueue.rval"); } } init_namedregs(&tmp->namedregs); @@ -586,7 +582,7 @@ wait_que(dbref player, int waittill, char *command, dbref cause, dbref sem, /* Put it on the end of the semaphore queue */ tmp->semattr = - mush_strdup(semattr ? semattr : "SEMAPHORE", "bqueue_semattr"); + mush_strdup(semattr ? semattr : "SEMAPHORE", "cqueue.semattr"); if (qsemlast != NULL) { qsemlast->next = tmp; qsemlast = tmp; diff --git a/src/create.c b/src/create.c index 7f347bd..cb0cbfe 100644 --- a/src/create.c +++ b/src/create.c @@ -458,10 +458,11 @@ do_dig(dbref player, const char *name, char **argv, int tport) * \param player the enactor. * \param name name of thing to create. * \param cost pennies spent in creation. + * \paran newdbref the (unparsed) dbref to give the object, or NULL to use the next free * \return dbref of new thing, or NOTHING. */ dbref -do_create(dbref player, char *name, int cost) +do_create(dbref player, char *name, int cost, char *newdbref) { struct module_entry_t *m; void (*handle)(dbref); @@ -477,6 +478,25 @@ do_create(dbref player, char *name, int cost) } else if (cost < OBJECT_COST) { cost = OBJECT_COST; } + + if (newdbref && *newdbref) { + /* move newdbref to the start of the free list */ + if (!has_flag_by_name(player, "WIZARD", NOTYPE)) { + notify(player, T("Permission denied.")); + return NOTHING; + } + thing = parse_dbref(newdbref); + if (thing == NOTHING || !GoodObject(thing) || !IsGarbage(thing)) { + notify(player, T("That is not a valid dbref.")); + return NOTHING; + } + + if (!make_first_free(thing)) { + notify(player, T("Unable to create object with that dbref.")); + return NOTHING; + } + } + if (can_pay_fees(player, cost)) { /* create the object */ thing = new_object(); @@ -533,7 +553,6 @@ clone_object(dbref player, dbref thing, const char *newname, int preserve) 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/cron.c b/src/cron.c index 3271961..35e6b8f 100644 --- a/src/cron.c +++ b/src/cron.c @@ -19,9 +19,7 @@ #include "cron.h" #include -#ifdef I_STRING #include -#endif #ifdef MUSHCRON diff --git a/src/db.c b/src/db.c index 360a5f5..b430c23 100644 --- a/src/db.c +++ b/src/db.c @@ -8,7 +8,7 @@ #include "copyrite.h" #include "config.h" - +#define _GNU_SOURCE #include #include #include @@ -21,6 +21,8 @@ #include #endif #include +#include +#include #include #include "conf.h" #include "dbio.h" @@ -87,22 +89,22 @@ HASHTAB htab_objdata_keys; /**< Object data keys hash table */ static void db_grow(dbref newtop); -static void db_write_obj_basic(FILE * f, dbref i, struct object *o); -int db_paranoid_write_object(FILE * f, dbref i, int flag); -void putlocks(FILE * f, lock_list *l); -void getlocks(dbref i, FILE * f); -void get_new_locks(dbref i, FILE * f, int c); -void db_read_attrs(FILE * f, dbref i, int c); -int get_list(FILE * f, dbref i); -static unsigned char * getbytes(FILE * f); -void putbytes(FILE * f, unsigned char *lbytes, int byte_limit); +static void db_write_obj_basic(PENNFILE * f, dbref i, struct object *o); +int db_paranoid_write_object(PENNFILE * f, dbref i, int flag); +void putlocks(PENNFILE * f, lock_list *l); +void getlocks(dbref i, PENNFILE * f); +void get_new_locks(dbref i, PENNFILE * f, int c); +void db_read_attrs(PENNFILE * f, dbref i, int c); +int get_list(PENNFILE * f, dbref i); +static unsigned char * getbytes(PENNFILE * f); +void putbytes(PENNFILE * f, unsigned char *lbytes, int byte_limit); void db_free(void); -int load_flag_db(FILE *); -void db_write_flag_db(FILE *); +int load_flag_db(PENNFILE *); +void db_write_flag_db(PENNFILE *); static void init_objdata_htab(int size, void(*free_data)(void*)); -static void db_write_flags(FILE * f); -static void db_write_powers(FILE * f); -static dbref db_read_oldstyle(FILE * f); +static void db_write_flags(PENNFILE * f); +static void db_write_powers(PENNFILE * f); +static dbref db_read_oldstyle(PENNFILE * f); StrTree object_names; /**< String tree of object names */ StrTree _clastmods; @@ -279,9 +281,9 @@ new_object(void) * \param ref value to write. */ void -putref(FILE * f, long int ref) +putref(PENNFILE *f, long int ref) { - OUTPUT(fprintf(f, "%ld\n", ref)); + penn_fprintf(f, "%ld\n", ref); } /** Output a string to a file. @@ -291,22 +293,22 @@ putref(FILE * f, long int ref) * \param s value to write. */ void -putstring(FILE * f, const char *s) +putstring(PENNFILE *f, const char *s) { - OUTPUT(putc('"', f)); + penn_fputc('"', f); while (*s) { switch (*s) { case '\\': case '"': - OUTPUT(putc('\\', f)); + penn_fputc('\\', f); /* FALL THROUGH */ default: - OUTPUT(putc(*s, f)); + penn_fputc(*s, f); } s++; } - OUTPUT(putc('"', f)); - OUTPUT(putc('\n', f)); + penn_fputc('"', f); + penn_fputc('\n', f); } /** Read a labeled entry from a database. @@ -320,7 +322,7 @@ putstring(FILE * f, const char *s) * buffer containing the value that was read. */ void -db_read_labeled_string(FILE * f, char **label, char **value) +db_read_labeled_string(PENNFILE *f, char **label, char **value) { static char lbuf[BUFFER_LEN], vbuf[BUFFER_LEN]; int c; @@ -334,14 +336,14 @@ db_read_labeled_string(FILE * f, char **label, char **value) dbline++; do { - c = getc(f); + c = penn_fgetc(f); while (isspace(c)) { if (c == '\n') dbline++; - c = getc(f); + c = penn_fgetc(f); } if (c == '#') { - while ((c = getc(f)) != '\n' && c != EOF) { + while ((c = penn_fgetc(f)) != '\n' && c != EOF) { /* nothing */ } if (c == '\n') @@ -365,7 +367,7 @@ db_read_labeled_string(FILE * f, char **label, char **value) longjmp(db_err, 1); } safe_chr(c, lbuf, &p); - c = getc(f); + c = penn_fgetc(f); } while (c != EOF && !isspace(c)); *p++ = '\0'; if (p >= lbuf + BUFFER_LEN) @@ -373,7 +375,7 @@ db_read_labeled_string(FILE * f, char **label, char **value) /* suck up separating whitespace */ while (c != '\n' && c != EOF && isspace(c)) - c = getc(f); + c = penn_fgetc(f); /* check for presence of a value, which we must have. */ if (c == EOF || c == '\n') { @@ -393,11 +395,11 @@ db_read_labeled_string(FILE * f, char **label, char **value) int sline; sline = dbline; for (;;) { - c = getc(f); + c = penn_fgetc(f); if (c == '"') break; if (c == '\\') - c = getc(f); + c = penn_fgetc(f); if (c == EOF) { do_rawlog(LT_ERR, "DB: Unclosed quoted string starting on line %d", sline); @@ -412,7 +414,7 @@ db_read_labeled_string(FILE * f, char **label, char **value) safe_chr(c, vbuf, &p); } do { - c = getc(f); + c = penn_fgetc(f); if (c != EOF && !isspace(c)) { do_rawlog(LT_ERR, "DB: Garbage after quoted string, line %d", dbline); longjmp(db_err, 1); @@ -428,7 +430,7 @@ db_read_labeled_string(FILE * f, char **label, char **value) longjmp(db_err, 1); } safe_chr(c, vbuf, &p); - c = getc(f); + c = penn_fgetc(f); } while (c != EOF && c != '\n'); if (c == '\n' && (p - vbuf >= 2) && (*(p - 2) == '\r')) { /* Oops, we read in \r\n at the end of this value. Drop the \r */ @@ -452,7 +454,7 @@ db_read_labeled_string(FILE * f, char **label, char **value) * buffer containing the value that was read. */ void -db_read_this_labeled_string(FILE * f, const char *label, char **value) +db_read_this_labeled_string(PENNFILE *f, const char *label, char **value) { char *readlabel; @@ -474,7 +476,7 @@ db_read_this_labeled_string(FILE * f, const char *label, char **value) * \param value pointer to update to the number that was read. */ void -db_read_this_labeled_int(FILE * f, const char *label, int *value) +db_read_this_labeled_int(PENNFILE *f, const char *label, int *value) { char *readlabel; char *readvalue; @@ -498,7 +500,7 @@ db_read_this_labeled_int(FILE * f, const char *label, int *value) * \param value pointer to update to the number that was read. */ void -db_read_labeled_int(FILE * f, char **label, int *value) +db_read_labeled_int(PENNFILE *f, char **label, int *value) { char *readvalue; db_read_labeled_string(f, label, &readvalue); @@ -513,7 +515,7 @@ db_read_labeled_int(FILE * f, char **label, int *value) * \param value pointer to update to the number that was read. */ void -db_read_this_labeled_uint32(FILE * f, const char *label, uint32_t * value) +db_read_this_labeled_uint32(PENNFILE *f, const char *label, uint32_t *value) { char *readlabel; char *readvalue; @@ -537,7 +539,7 @@ db_read_this_labeled_uint32(FILE * f, const char *label, uint32_t * value) * \param value pointer to update to the number that was read. */ void -db_read_labeled_uint32(FILE * f, char **label, uint32_t * value) +db_read_labeled_uint32(PENNFILE *f, char **label, uint32_t *value) { char *readvalue; db_read_labeled_string(f, label, &readvalue); @@ -554,7 +556,7 @@ db_read_labeled_uint32(FILE * f, char **label, uint32_t * value) * \param value pointer to update to the time_t that was read. */ void -db_read_this_labeled_time_t(FILE * f, const char *label, time_t *value) +db_read_this_labeled_time_t(PENNFILE * f, const char *label, time_t *value) { char *readlabel; char *readvalue; @@ -578,7 +580,7 @@ db_read_this_labeled_time_t(FILE * f, const char *label, time_t *value) * \param value pointer to update to the time_t that was read. */ void -db_read_labeled_time_t(FILE * f, char **label, time_t *value) +db_read_labeled_time_t(PENNFILE * f, char **label, time_t *value) { char *readvalue; db_read_labeled_string(f, label, &readvalue); @@ -593,7 +595,7 @@ db_read_labeled_time_t(FILE * f, char **label, time_t *value) * \param value pointer to update to the dbref that was read. */ void -db_read_this_labeled_dbref(FILE * f, const char *label, dbref *val) +db_read_this_labeled_dbref(PENNFILE *f, const char *label, dbref *val) { char *readlabel; char *readvalue; @@ -616,7 +618,7 @@ db_read_this_labeled_dbref(FILE * f, const char *label, dbref *val) * \param value pointer to update to the dbref that was read. */ void -db_read_labeled_dbref(FILE * f, char **label, dbref *val) +db_read_labeled_dbref(PENNFILE *f, char **label, dbref *val) { char *readvalue; db_read_labeled_string(f, label, &readvalue); @@ -624,35 +626,35 @@ db_read_labeled_dbref(FILE * f, char **label, dbref *val) } static void -db_write_label(FILE * f, char const *l) +db_write_label(PENNFILE * f, char const *l) { - OUTPUT(fputs(l, f)); - OUTPUT(putc(' ', f)); + penn_fputs(l, f); + penn_fputc(' ', f); } void -db_write_labeled_string(FILE * f, char const *label, char const *value) +db_write_labeled_string(PENNFILE * f, char const *label, char const *value) { db_write_label(f, label); putstring(f, value); } void -db_write_labeled_int(FILE * f, char const *label, int value) +db_write_labeled_int(PENNFILE * f, char const *label, int value) { - OUTPUT(fprintf(f, "%s %d\n", label, value)); + penn_fprintf(f, "%s %d\n", label, value); } void -db_write_labeled_time_t(FILE * f, char const *label, time_t value) +db_write_labeled_time_t(PENNFILE * f, char const *label, time_t value) { - OUTPUT(fprintf(f, "%s %zu\n", label, value)); + penn_fprintf(f, "%s %zu\n", label, value); } void -db_write_labeled_dbref(FILE * f, char const *label, dbref value) +db_write_labeled_dbref(PENNFILE * f, char const *label, dbref value) { - OUTPUT(fprintf(f, "%s #%d\n", label, value)); + penn_fprintf(f, "%s #%d\n", label, value); } /** Write a boolexp to a file in unparsed (text) form. @@ -660,7 +662,7 @@ db_write_labeled_dbref(FILE * f, char const *label, dbref value) * \param b pointer to boolexp to write. */ void -putboolexp(FILE * f, boolexp b) +putboolexp(PENNFILE *f, boolexp b) { db_write_labeled_string(f, " key", unparse_boolexp(GOD, b, UB_DBREF)); } @@ -670,7 +672,7 @@ putboolexp(FILE * f, boolexp b) * \param l pointer to lock_list to write. */ void -putlocks(FILE * f, lock_list *l) +putlocks(PENNFILE *f, lock_list *l) { lock_list *ll; int count = 0; @@ -696,7 +698,7 @@ putlocks(FILE * f, lock_list *l) * \param o pointer to object to write. */ static void -db_write_obj_basic(FILE * f, dbref i, struct object *o) +db_write_obj_basic(PENNFILE *f, dbref i, struct object *o) { db_write_labeled_string(f, "name", o->name); db_write_labeled_dbref(f, "location", o->location); @@ -731,7 +733,7 @@ db_write_obj_basic(FILE * f, dbref i, struct object *o) * \param i dbref of object to write. */ int -db_write_object(FILE * f, dbref i) +db_write_object(PENNFILE *f, dbref i) { struct object *o; ALIST *list; @@ -784,7 +786,7 @@ db_write_object(FILE * f, dbref i) * \return the number of objects in the database (db_top) */ dbref -db_write(FILE * f, int flag) +db_write(PENNFILE *f, int flag) { dbref i; int dbflag; @@ -818,10 +820,10 @@ db_write(FILE * f, int flag) dbflag += DBF_NEW_ATR_LOCK; dbflag += DBF_ATR_MODTIME; - OUTPUT(fprintf(f, "+V%d\n", dbflag * 256 + 2)); + penn_fprintf(f, "+V%d\n", dbflag * 256 + 2); db_write_labeled_string(f, "savedtime", show_time(mudtime, 1)); - OUTPUT(fprintf(f, "~%d\n", db_top)); + penn_fprintf(f, "~%d\n", db_top); for (i = 0; i < db_top; i++) { #ifdef WIN32 #ifndef __MINGW32__ @@ -832,23 +834,23 @@ db_write(FILE * f, int flag) #endif if (IsGarbage(i)) continue; - OUTPUT(fprintf(f, "!%d\n", i)); + penn_fprintf(f, "!%d\n", i); db_write_object(f, i); } - OUTPUT(fputs(EOD, f)); + penn_fputs(EOD, f); return db_top; } static void -db_write_flags(FILE * f) +db_write_flags(PENNFILE * f) { - OUTPUT(fprintf(f, "+FLAGS LIST\n")); + penn_fprintf(f, "+FLAGS LIST\n"); flag_write_all(f, "FLAG"); } static void -db_write_powers(FILE *f) { - OUTPUT(fprintf(f, "+POWERS LIST\n")); +db_write_powers(PENNFILE *f) { + penn_fprintf(f, "+POWERS LIST\n"); power_write_all(f); } @@ -862,7 +864,7 @@ db_write_powers(FILE *f) { * \param flag 1 = debug, 0 = normal */ int -db_paranoid_write_object(FILE * f, dbref i, int flag) +db_paranoid_write_object(PENNFILE *f, dbref i, int flag) { struct object *o; ALIST *list, *next; @@ -986,7 +988,7 @@ db_paranoid_write_object(FILE * f, dbref i, int flag) * \return the number of objects in the database (db_top) */ dbref -db_paranoid_write(FILE * f, int flag) +db_paranoid_write(PENNFILE *f, int flag) { dbref i; int dbflag; @@ -1018,12 +1020,12 @@ db_paranoid_write(FILE * f, int flag) do_rawlog(LT_CHECK, "PARANOID WRITE BEGINNING...\n"); - OUTPUT(fprintf(f, "+V%d\n", dbflag * 256 + 2)); + penn_fprintf(f, "+V%d\n", dbflag * 256 + 2); db_write_labeled_string(f, "savedtime", show_time(mudtime, 1)); db_write_flags(f); db_write_powers(f); - OUTPUT(fprintf(f, "~%d\n", db_top)); + penn_fprintf(f, "~%d\n", db_top); /* write out each object */ for (i = 0; i < db_top; i++) { @@ -1034,13 +1036,13 @@ db_paranoid_write(FILE * f, int flag) #endif if (IsGarbage(i)) continue; - OUTPUT(fprintf(f, "!%d\n", i)); + penn_fprintf(f, "!%d\n", i); db_paranoid_write_object(f, i, flag); /* print out a message every so many objects */ if (i % globals.paranoid_checkpt == 0) do_rawlog(LT_CHECK, T("\t...wrote up to object #%d\n"), i); } - OUTPUT(fputs(EOD, f)); + penn_fputs(EOD, f); do_rawlog(LT_CHECK, T("\t...finished at object #%d\n"), i - 1); do_rawlog(LT_CHECK, "END OF PARANOID WRITE.\n"); return db_top; @@ -1052,10 +1054,10 @@ db_paranoid_write(FILE * f, int flag) * \return long int read. */ long int -getref(FILE * f) +getref(PENNFILE *f) { static char buf[BUFFER_LEN]; - if (!fgets(buf, sizeof(buf), f)) { + if (!penn_fgets(buf, sizeof(buf), f)) { do_rawlog(LT_ERR, T("Unexpected EOF at line %d"), dbline); longjmp(db_err, 1); } @@ -1073,14 +1075,14 @@ getref(FILE * f) * \return pointer to static buffer containing string read. */ char * -getstring_noalloc(FILE * f) +getstring_noalloc(PENNFILE *f) { static char buf[BUFFER_LEN]; char *p; int c; p = buf; - c = fgetc(f); + c = penn_fgetc(f); if (c == EOF) { do_rawlog(LT_ERR, T("Unexpected EOF at line %d"), dbline); longjmp(db_err, 1); @@ -1094,26 +1096,26 @@ getstring_noalloc(FILE * f) return buf; } safe_chr(c, buf, &p); - c = fgetc(f); + c = penn_fgetc(f); } } else { for (;;) { - c = fgetc(f); + c = penn_fgetc(f); if (c == '"') { /* It's a closing quote if it's followed by \r or \n */ - c = fgetc(f); + c = penn_fgetc(f); if (c == '\r') { /* Get a possible \n, too */ - if ((c = fgetc(f)) != '\n') - ungetc(c, f); + if ((c = penn_fgetc(f)) != '\n') + penn_ungetc(c, f); else dbline++; } else if (c != '\n') - ungetc(c, f); + penn_ungetc(c, f); *p = '\0'; return buf; } else if (c == '\\') { - c = fgetc(f); + c = penn_fgetc(f); } if ((c == '\0') || (c == EOF)) { *p = '\0'; @@ -1132,7 +1134,7 @@ getstring_noalloc(FILE * f) * \return pointer to boolexp read. */ boolexp -getboolexp(FILE * f, const char *type) +getboolexp(PENNFILE *f, const char *type) { char *val; db_read_this_labeled_string(f, "key", &val); @@ -1149,7 +1151,7 @@ extern PRIV lock_privs[]; * \param c number of locks, or -1 if not yet known. */ void -get_new_locks(dbref i, FILE * f, int c) +get_new_locks(dbref i, PENNFILE *f, int c) { char *val, *key; dbref creator; @@ -1166,8 +1168,8 @@ get_new_locks(dbref i, FILE * f, int c) for (;;) { int ch; - ch = fgetc(f); - ungetc(ch, f); + ch = penn_fgetc(f); + penn_ungetc(ch, f); if (ch != ' ') break; @@ -1210,15 +1212,15 @@ get_new_locks(dbref i, FILE * f, int c) * \param f file pointer to read from. */ void -getlocks(dbref i, FILE * f) +getlocks(dbref i, PENNFILE *f) { /* Assumes it begins at the beginning of a line. */ int c; boolexp b; char buf[BUFFER_LEN], *p; - while ((c = getc(f)), c != EOF && c == '_') { + while ((c = penn_fgetc(f)), c != EOF && c == '_') { p = buf; - while ((c = getc(f)), c != EOF && c != '|') { + while ((c = penn_fgetc(f)), c != EOF && c != '|') { *p++ = c; } *p = '\0'; @@ -1234,47 +1236,47 @@ getlocks(dbref i, FILE * f) add_lock_raw(Owner(i), i, buf, b, LF_DEFAULT); } } - ungetc(c, f); + penn_ungetc(c, f); return; } void -putbytes(FILE * f, unsigned char *lbytes, int byte_limit) { +putbytes(PENNFILE * f, unsigned char *lbytes, int byte_limit) { int i; - OUTPUT(putc('\"', f)); + penn_fputc('\"', f); for(i = 0; i < byte_limit; ++i) { switch(lbytes[i]) { case '\"': case '\\': - OUTPUT(putc('\\', f)); + penn_fputc('\\', f); default: - OUTPUT(putc(lbytes[i], f)); + penn_fputc(lbytes[i], f); } } - OUTPUT(putc('\"', f)); - OUTPUT(putc('\n', f)); + penn_fputc('\"', f); + penn_fputc('\n', f); } unsigned char * -getbytes(FILE * f) { +getbytes(PENNFILE * f) { static unsigned char byte_buf[BUFFER_LEN]; unsigned char *bp; int i; memset(byte_buf, 0, BUFFER_LEN); bp = byte_buf; - (void) fgetc(f); /* Skip the leading " */ + (void) penn_fgetc(f); /* Skip the leading " */ for(;;) { - i = fgetc(f); + i = penn_fgetc(f); if(i == '\"') { - if((i = fgetc(f)) != '\n') - ungetc(i, f); + if((i = penn_fgetc(f)) != '\n') + penn_ungetc(i, f); break; } else if(i == '\\') { - i = fgetc(f); + i = penn_fgetc(f); } if(i == EOF) break; @@ -1313,7 +1315,7 @@ db_free(void) * \param i dbref for the attribute list. */ int -get_list(FILE * f, dbref i) +get_list(PENNFILE *f, dbref i) { int c; char *p, *q; @@ -1328,12 +1330,12 @@ get_list(FILE * f, dbref i) List(i) = NULL; tbuf1[0] = '\0'; while (1) - switch (c = getc(f)) { + switch (c = penn_fgetc(f)) { case ']': /* new style attribs, read name then value */ /* Using getstring_noalloc here will cause problems with attribute names starting with ". This is probably a better fix than just disallowing " in attribute names. */ - fgets(tbuf1, BUFFER_LEN + 150, f); + penn_fgets(tbuf1, BUFFER_LEN + 150, f); if (!(p = strchr(tbuf1, '^'))) { do_rawlog(LT_ERR, T("ERROR: Bad format on new attributes. object #%d"), i); @@ -1389,7 +1391,7 @@ get_list(FILE * f, dbref i) return -1; break; case '<': /* end of list */ - if ('\n' != getc(f)) { + if ('\n' != penn_fgetc(f)) { do_rawlog(LT_ERR, T("ERROR: no line feed after < on object %d"), i); return -1; } @@ -1416,7 +1418,7 @@ get_list(FILE * f, dbref i) extern PRIV attr_privs_view[]; void -db_read_attrs(FILE * f, dbref i, int count) +db_read_attrs(PENNFILE *f, dbref i, int count) { char name[ATTRIBUTE_NAME_LIMIT + 1]; char l_key[BUFFER_LEN]; @@ -1435,8 +1437,8 @@ db_read_attrs(FILE * f, dbref i, int count) for(;;) { int c; - c = fgetc(f); - ungetc(c, f); + c = penn_fgetc(f); + penn_ungetc(c, f); if (c != ' ') break; @@ -1495,13 +1497,13 @@ db_read_attrs(FILE * f, dbref i, int count) /* Load Seperate Flag Database */ -int load_flag_db(FILE *f) { +int load_flag_db(PENNFILE *f) { int c; char *tmp; loading_db = 1; - if((c = fgetc(f)) != '+' && (c = fgetc(f)) != '+') { + if((c = penn_fgetc(f)) != '+' && (c = penn_fgetc(f)) != '+') { do_rawlog(LT_ERR, T("Flag database does not start with a version string")); return -1; } @@ -1511,9 +1513,9 @@ int load_flag_db(FILE *f) { db_read_this_labeled_string(f, "savedtime", &tmp); /* We don't use this info anywhere 'yet' */ do_rawlog(LT_ERR, T("Loading flag databased saved on %s UTC"), tmp); - while((c = fgetc(f)) != EOF) { + while((c = penn_fgetc(f)) != EOF) { if(c == '+') { - c = fgetc(f); + c = penn_fgetc(f); if(c == 'F') { (void) getstring_noalloc(f); flag_read_all(f, "FLAG"); @@ -1526,8 +1528,8 @@ int load_flag_db(FILE *f) { } } else if(c == '*'){ char buff[80]; - ungetc('*', f); - fgets(buff, sizeof buff, f); + penn_ungetc('*', f); + penn_fgets(buff, sizeof buff, f); if(strcmp(buff, EOD) != 0){ do_rawlog(LT_ERR, T("ERROR: No end of dump entry.")); return -1; @@ -1544,7 +1546,7 @@ int load_flag_db(FILE *f) { return 0; } -void db_write_flag_db(FILE *f) { +void db_write_flag_db(PENNFILE *f) { int flags; /* Write out db flags */ @@ -1552,11 +1554,11 @@ void db_write_flag_db(FILE *f) { flags += FLAG_DBF_CQUOTA_RENAME; /* */ - OUTPUT(fprintf(f, "+V%ld\n", flagdb_flags * 256 + 2)); + penn_fprintf(f, "+V%ld\n", flagdb_flags * 256 + 2); db_write_labeled_string(f, "savedtime", show_time(mudtime, 1)); db_write_flags(f); db_write_powers(f); - OUTPUT(fputs(EOD, f)); + penn_fputs(EOD, f); } @@ -1567,7 +1569,7 @@ void db_write_flag_db(FILE *f) { */ static dbref -db_read_oldstyle(FILE * f) +db_read_oldstyle(PENNFILE *f) { int c, opbits; dbref i; @@ -1579,7 +1581,7 @@ db_read_oldstyle(FILE * f) for (i = 0;; i++) { /* Loop invariant: we always begin at the beginning of a line. */ errobj = i; - c = getc(f); + c = penn_fgetc(f); switch (c) { /* make sure database is at least this big *1.5 */ case '~': @@ -1588,7 +1590,7 @@ db_read_oldstyle(FILE * f) break; /* Use the MUSH 2.0 header stuff to see what's in this db */ case '+': - c = getc(f); /* Skip the V */ + c = penn_fgetc(f); /* Skip the V */ if (c == 'F') { (void) getstring_noalloc(f); flag_read_all(f, "FLAG"); @@ -1754,8 +1756,8 @@ db_read_oldstyle(FILE * f) case '*': { char buff[80]; - ungetc('*', f); - fgets(buff, sizeof buff, f); + penn_ungetc('*', f); + penn_fgets(buff, sizeof buff, f); if (strcmp(buff, EOD) != 0) { do_rawlog(LT_ERR, T("ERROR: No end of dump after object #%d"), i - 1); return -1; @@ -1823,7 +1825,7 @@ db_read_oldstyle(FILE * f) * \return number of objects in the database. */ dbref -db_read(FILE * f) +db_read(PENNFILE *f) { int c; dbref i = 0; @@ -1847,12 +1849,12 @@ db_read(FILE * f) db_free(); indb_flags = 1; - c = fgetc(f); + c = penn_fgetc(f); if (c != '+') { do_rawlog(LT_ERR, T("Database does not start with a version string")); return -1; } - c = fgetc(f); + c = penn_fgetc(f); if (c != 'V') { do_rawlog(LT_ERR, T("Database does not start with a version string")); return -1; @@ -1878,10 +1880,10 @@ db_read(FILE * f) do_rawlog(LT_ERR, T("Loading database saved on %s UTC"), db_timestamp); - while ((c = fgetc(f)) != EOF) { + while ((c = penn_fgetc(f)) != EOF) { switch (c) { case '+': - c = fgetc(f); + c = penn_fgetc(f); if (c == 'F') { (void) getstring_noalloc(f); flag_read_all(f, "FLAG"); @@ -1955,8 +1957,8 @@ db_read(FILE * f) db_grow(i + 1); o = db + i; while (1) { - c = fgetc(f); - ungetc(c, f); + c = penn_fgetc(f); + penn_ungetc(c, f); /* At the start of another object or the EOD marker */ if (c == '!' || c == '*') break; @@ -2106,8 +2108,8 @@ db_read(FILE * f) case '*': { char buff[80]; - ungetc('*', f); - fgets(buff, sizeof buff, f); + penn_ungetc('*', f); + penn_fgets(buff, sizeof buff, f); if (strcmp(buff, EOD) != 0) { do_rawlog(LT_ERR, T("ERROR: No end of dump after object #%d"), i - 1); return -1; @@ -2335,3 +2337,201 @@ create_minimal_db(void) #endif mail_init(); } + + +/** Run a function, and jump if error */ +#define OUTPUT(fun) do { if ((fun) < 0) longjmp(db_err, 1); } while (0) + +/* Wrapper for fopen for use in reboot code. */ +PENNFILE * +penn_fopen(const char *filename, const char *mode) +{ + PENNFILE *pf; + + pf = mush_malloc(sizeof *pf, "pennfile"); + pf->type = PFT_FILE; + pf->handle.f = fopen(filename, mode); + if (!pf->handle.f) { + do_rawlog(LT_ERR, "Unable to open %s in mode '%s': %s", + filename, mode, strerror(errno)); + mush_free(pf, "pennfile"); + return NULL; + } + return pf; +} + +/* Close a db file, which may really be a pipe */ +void +penn_fclose(PENNFILE *pf) +{ + switch (pf->type) { + case PFT_PIPE: +#ifndef WIN32 + pclose(pf->handle.f); +#endif + break; + case PFT_FILE: + fclose(pf->handle.f); + break; + case PFT_GZFILE: +#ifdef HAVE_LIBZ + gzclose(pf->handle.g); +#endif + break; + } + mush_free(pf, "pennfile"); +} + + +int +penn_fgetc(PENNFILE *f) +{ + switch (f->type) { + case PFT_FILE: + case PFT_PIPE: + return fgetc(f->handle.f); + break; + case PFT_GZFILE: +#ifdef HAVE_LIBZ + return gzgetc(f->handle.g); +#endif + break; + } + return 0; +} + +char * +penn_fgets(char *buf, int len, PENNFILE *pf) +{ + switch (pf->type) { + case PFT_FILE: + case PFT_PIPE: + return fgets(buf, len, pf->handle.f); + case PFT_GZFILE: +#ifdef HAVE_LIBZ + return gzgets(pf->handle.g, buf, len); +#endif + break; + } + return NULL; +} + +int +penn_fputc(int c, PENNFILE *f) +{ + switch (f->type) { + case PFT_FILE: + case PFT_PIPE: + OUTPUT(fputc(c, f->handle.f)); + break; + case PFT_GZFILE: +#ifdef HAVE_LIBZ + OUTPUT(gzputc(f->handle.g, c)); +#endif + break; + } + return 0; +} + +int +penn_fputs(const char *s, PENNFILE *f) +{ + switch (f->type) { + case PFT_FILE: + case PFT_PIPE: + OUTPUT(fputs(s, f->handle.f)); + break; + case PFT_GZFILE: +#ifdef HAVE_LIBZ + OUTPUT(gzputs(f->handle.g, s)); +#endif + } + return 0; +} + +int +penn_fprintf(PENNFILE *f, const char *fmt, ...) +{ + va_list ap; + int r = -1; + + switch (f->type) { + case PFT_FILE: + case PFT_PIPE: + va_start(ap, fmt); + r = vfprintf(f->handle.f, fmt, ap); + va_end(ap); + if (r < 0) + longjmp(db_err, 1); + break; + case PFT_GZFILE: +#ifdef HAVE_LIBZ + /* No equivalent to vfprintf in zlib... */ +#ifdef HAVE_VASPRINTF + { /* Safe GNU/BSD way */ + char *line = NULL; + va_start(ap, fmt); + r = vasprintf(&line, fmt, ap); + va_end(ap); + if (r > -1) { + OUTPUT(gzputs(f->handle.g, line)); + free(line); + } else + longjmp(db_err, 1); + } +#else + { + char line[BUFFER_LEN * 2]; + + va_start(ap, fmt); +#ifdef HAVE_VSNPRINTF + r = vsnprintf(line, sizeof line, fmt, ap); +#else + r = vsprintf(line, fmt, ap); +#endif + va_end(ap, fmt); + if (r > -1) + OUTPUT(gzputs(f->handle.g, line)); + else + longjmp(db_err, 1); + } +#endif +#endif + break; + } + return r; +} + +int +penn_ungetc(int c, PENNFILE *f) +{ + switch (f->type) { + case PFT_FILE: + case PFT_PIPE: + OUTPUT(ungetc(c, f->handle.f)); + break; + case PFT_GZFILE: +#ifdef HAVE_LIBZ + OUTPUT(gzungetc(c, f->handle.g)); +#endif + break; + } + return c; + +} + +int +penn_feof(PENNFILE *pf) +{ + switch (pf->type) { + case PFT_FILE: + case PFT_PIPE: + return feof(pf->handle.f); + case PFT_GZFILE: +#ifdef HAVE_LIBZ + return gzeof(pf->handle.g); +#endif + break; + } + return 0; +} diff --git a/src/destroy.c b/src/destroy.c index 7eb5400..f954a6f 100644 --- a/src/destroy.c +++ b/src/destroy.c @@ -928,6 +928,32 @@ clear_exit(dbref thing) giveto(Owner(thing), EXIT_COST); } +/** If object is in the free list, move it to the very beginning. + * \param object dbref of object to move + * \return 1 if object is moved successfully, 0 otherwise + */ +int +make_first_free(dbref object) +{ + dbref curr; + dbref prev = NOTHING; + + if (first_free == NOTHING || !GoodObject(object) || !IsGarbage(object)) + return 0; /* no garbage, or object isn't garbage */ + else if (first_free == object) + return 1; /* object is already at the head of the queue */ + for (curr = first_free; Next(curr); curr = Next(curr)) { + if (curr == object) { + Next(prev) = Next(curr); + Next(curr) = first_free; + first_free = curr; + return 1; + } else + prev = curr; + } + return 0; + +} /** Return a cleaned up object off the free list or NOTHING. * \return a garbage object or NOTHING. diff --git a/src/division.c b/src/division.c index f657a06..297f438 100644 --- a/src/division.c +++ b/src/division.c @@ -38,9 +38,9 @@ static void power_add(POWER * pow); static POWER *new_power(void); static void realloc_object_powers(int); static void power_add_additional(); -static void power_read(FILE *); -static void powergroup_read(FILE *); -static void power_read_alias(FILE *); +static void power_read(PENNFILE *); +static void powergroup_read(PENNFILE *); +static void power_read_alias(PENNFILE *); static void clear_all_powers(); static int power_delete(const char *); static int check_old_power_ycode(int, unsigned char *); @@ -65,7 +65,7 @@ int can_have_power_at(dbref, POWER *); POWER *add_power_type(const char *name, const char *type); void init_powers(); div_pbits new_power_bitmask(); -void powers_read_all(FILE * in); +void powers_read_all(PENNFILE * in); POWER *has_power(dbref, const char *); int can_have_pg(dbref object, POWERGROUP * pgrp); void do_list_powers(dbref player, const char *name); @@ -349,7 +349,7 @@ PTAB powergroup_ptab; /* Database Functions {{{2 */ /* powers_read_all() {{{3 */ void -powers_read_all(FILE * in) +powers_read_all(PENNFILE * in) { int count; @@ -403,7 +403,7 @@ init_powers() /* powers_read() {{{3 - database power read routine */ static void -power_read(FILE * in) +power_read(PENNFILE * in) { char power_name[BUFFER_LEN]; char *power_type; @@ -422,7 +422,7 @@ power_read(FILE * in) /* powergroup_read() {{{3 - database powergroup read routine */ static void -powergroup_read(FILE * in) +powergroup_read(PENNFILE * in) { POWERGROUP *pgrp; div_pbits dbits; @@ -451,7 +451,7 @@ powergroup_read(FILE * in) /* power_read_alias() {{{3 */ static void -power_read_alias(FILE * in) +power_read_alias(PENNFILE * in) { POWER *power; char alias_name[BUFFER_LEN]; @@ -476,7 +476,7 @@ power_read_alias(FILE * in) /* power_write_all() {{{3 */ void -power_write_all(FILE * file) +power_write_all(PENNFILE * file) { POWER *power; POWERGROUP *pgrp; @@ -1603,7 +1603,7 @@ create_div(dbref owner, const char *name) } Parent(obj) = SDIV(owner).object; current_state.divisions++; - sprintf(buf, object_header(owner, obj)); + strcpy(buf, object_header(owner, obj)); notify_format(owner, T("Division created: %s Parent division: %s"), buf, buf2); return obj; diff --git a/src/extmail.c b/src/extmail.c index 10f98c7..b925a55 100644 --- a/src/extmail.c +++ b/src/extmail.c @@ -1,3 +1,4 @@ + /** * \file extmail.c * @@ -1884,7 +1885,7 @@ FUNCTION(fun_mailsubject) * \return number of mail messages saved. */ int -dump_mail(FILE * fp) +dump_mail(PENNFILE *fp) { MAIL *mp; int count = 0; @@ -1896,11 +1897,11 @@ dump_mail(FILE * fp) mail_flags += MDBF_SENDERCTIME; if (mail_flags) - fprintf(fp, "+%d\n", mail_flags); + penn_fprintf(fp, "+%d\n", mail_flags); save_malias(fp); - OUTPUT(fprintf(fp, "%d\n", mdb_top)); + penn_fprintf(fp, "%d\n", mdb_top); for (mp = HEAD; mp != NULL; mp = mp->next) { putref(fp, mp->to); @@ -1916,15 +1917,14 @@ dump_mail(FILE * fp) count++; } - OUTPUT(fputs(EOD, fp)); - fflush(fp); + penn_fputs(EOD, fp); if (count != mdb_top) { do_log(LT_ERR, 0, 0, T("MAIL: Count of messages is %d, mdb_top is %d."), count, mdb_top); mdb_top = count; /* Doesn't help if we forked, but oh well */ } - return (count); + return count; } @@ -2014,7 +2014,7 @@ mail_init(void) * \param fp pointer to filehandle from which to load mail. */ int -load_mail(FILE * fp) +load_mail(PENNFILE *fp) { char nbuf1[8]; unsigned char *tbuf = NULL; @@ -2029,7 +2029,7 @@ load_mail(FILE * fp) struct tm ttm; /* find out how many messages we should be loading */ - fgets(nbuf1, sizeof(nbuf1), fp); + penn_fgets(nbuf1, sizeof(nbuf1), fp); /* If it starts with +, it's telling us the mail db flags */ if (*nbuf1 == '+') { mail_flags = atoi(nbuf1 + 1); @@ -2037,14 +2037,14 @@ load_mail(FILE * fp) if (mail_flags & MDBF_ALIASES) { load_malias(fp); } - fgets(nbuf1, sizeof(nbuf1), fp); + penn_fgets(nbuf1, sizeof(nbuf1), fp); } mail_top = atoi(nbuf1); if (!mail_top) { /* mail_top could be 0 from an error or actually be 0. */ if (nbuf1[0] == '0' && nbuf1[1] == '\n') { char buff[20]; - if (!fgets(buff, sizeof buff, fp)) + if (!penn_fgets(buff, sizeof buff, fp)) do_rawlog(LT_ERR, T("MAIL: Missing end-of-dump marker in mail database.")); else if (strcmp(buff, (mail_flags & MDBF_NEW_EOD) @@ -2159,7 +2159,7 @@ load_mail(FILE * fp) } { char buff[20]; - if (!fgets(buff, sizeof buff, fp)) + if (!penn_fgets(buff, sizeof buff, fp)) do_rawlog(LT_ERR, T("MAIL: Missing end-of-dump marker in mail database.")); else if (strcmp(buff, (mail_flags & MDBF_NEW_EOD) diff --git a/src/flags.c b/src/flags.c index 5f67a94..2109d09 100644 --- a/src/flags.c +++ b/src/flags.c @@ -60,10 +60,10 @@ static FLAG *letter_to_flagptr(FLAGSPACE * n, char c, int type); static void flag_add(FLAGSPACE * n, const char *name, FLAG *f); static int has_flag(dbref thing, FLAG *f); -static FLAG *flag_read(FILE * in); -static FLAG *flag_read_oldstyle(FILE * in); -static void flag_read_all_oldstyle(FILE * in, const char *ns); -static void flag_write(FILE * out, FLAG *f, const char *name); +static FLAG *flag_read(PENNFILE * in); +static FLAG *flag_read_oldstyle(PENNFILE * in); +static void flag_read_all_oldstyle(PENNFILE * in, const char *ns); +static void flag_write(PENNFILE * out, FLAG *f, const char *name); static FLAG *flag_hash_lookup(FLAGSPACE * n, const char *name, int type); static FLAG *clone_flag(FLAG *f); static FLAG *new_flag(void); @@ -71,7 +71,7 @@ static void flag_add_additional(void); static char *list_aliases(FLAGSPACE * n, FLAG *given); static void realloc_object_flag_bitmasks(int numbytes); static FLAG *match_flag_ns(FLAGSPACE * n, const char *name); -static void flag_fake_read(FILE *); +static void flag_fake_read(PENNFILE *); PTAB ptab_flag; /**< Table of flags by name, inc. aliases */ HASHTAB htab_flagspaces; /**< Hash of flagspaces */ @@ -424,7 +424,7 @@ realloc_object_flag_bitmasks(int numbytes) /* Read in a flag from a file and return it */ static FLAG * -flag_read_oldstyle(FILE * in) +flag_read_oldstyle(PENNFILE *in) { FLAG *f; char *c; @@ -445,7 +445,7 @@ flag_read_oldstyle(FILE * in) } static FLAG * -flag_alias_read_oldstyle(FILE * in, char *alias) +flag_alias_read_oldstyle(PENNFILE * in, char *alias) { FLAG *f; char *c; @@ -484,7 +484,7 @@ flag_alias_read_oldstyle(FILE * in, char *alias) * \param ns name of namespace to search. */ static void -flag_read_all_oldstyle(FILE * in, const char *ns) +flag_read_all_oldstyle(PENNFILE *in, const char *ns) { FLAG *f; FLAGSPACE *n; @@ -508,7 +508,7 @@ flag_read_all_oldstyle(FILE * in, const char *ns) /* Read in a flag from a file and return it */ static FLAG * -flag_read(FILE * in) +flag_read(PENNFILE *in) { FLAG *f; char *c; @@ -538,7 +538,7 @@ flag_read(FILE * in) } static FLAG * -flag_alias_read(FILE * in, char *alias, FLAGSPACE *n) +flag_alias_read(PENNFILE *in, char *alias, FLAGSPACE *n) { FLAG *f; char *c; @@ -574,7 +574,7 @@ flag_alias_read(FILE * in, char *alias, FLAGSPACE *n) * \param ns name of namespace to search. */ void -flag_read_all(FILE * in, const char *ns) +flag_read_all(PENNFILE *in, const char *ns) { FLAG *f; FLAGSPACE *n; @@ -603,8 +603,8 @@ flag_read_all(FILE * in, const char *ns) for (;;) { int c; - c = fgetc(in); - ungetc(c, in); + c = penn_fgetc(in); + penn_ungetc(c, in); if (c != ' ') break; @@ -625,8 +625,8 @@ flag_read_all(FILE * in, const char *ns) for (found = 0 ;;) { int c; - c = fgetc(in); - ungetc(c, in); + c = penn_fgetc(in); + penn_ungetc(c, in); if (c != ' ') break; @@ -645,7 +645,7 @@ flag_read_all(FILE * in, const char *ns) flag_add_additional(); } -static void flag_fake_read(FILE *f) { +static void flag_fake_read(PENNFILE *f) { int count; /* Read shit into NULL-ville */ @@ -668,7 +668,7 @@ static void flag_fake_read(FILE *f) { /* Write a flag out to a file */ static void -flag_write(FILE * out, FLAG *f, const char *name) +flag_write(PENNFILE *out, FLAG *f, const char *name) { db_write_labeled_string(out, " name", name); db_write_labeled_string(out, " letter", tprintf("%c", f->letter)); @@ -682,7 +682,7 @@ flag_write(FILE * out, FLAG *f, const char *name) /* Write a flag alias out to a file */ static void -flag_alias_write(FILE * out, FLAG *f, const char *name) +flag_alias_write(PENNFILE *out, FLAG *f, const char *name) { db_write_labeled_string(out, " name", f->name); db_write_labeled_string(out, " alias", name); @@ -694,7 +694,7 @@ flag_alias_write(FILE * out, FLAG *f, const char *name) * \param out file pointer to write to. */ void -flag_write_all(FILE * out, const char *ns) +flag_write_all(PENNFILE *out, const char *ns) { int i, count; FLAG *f; @@ -1447,6 +1447,7 @@ set_flag(dbref player, dbref thing, const char *flag, int negate, dbref icloc, absroom; #endif /* RPMODE_SYS */ FLAGSPACE *n; + int current; n = (FLAGSPACE *) hashfind("FLAG", &htab_flagspaces); if ((f = flag_hash_lookup(n, flag, Typeof(thing))) == NULL) { @@ -1547,6 +1548,8 @@ set_flag(dbref player, dbref thing, const char *flag, int negate, twiddle_flag(thing, f, negate); + current = sees_flag(player, thing, f->name); + #ifdef RPMODE_SYS if(is_flag(f, "RPMODE")) { dbref oldloc; @@ -1680,6 +1683,8 @@ set_flag(dbref player, dbref thing, const char *flag, int negate, safe_str(Name(thing), tbuf1, &tp); safe_str(" - ", tbuf1, &tp); safe_str(f->name, tbuf1, &tp); + if (!current) + safe_str(" (already)", tbuf1, &tp); safe_str(T(" reset."), tbuf1, &tp); *tp = '\0'; notify(player, tbuf1); @@ -1752,6 +1757,8 @@ set_flag(dbref player, dbref thing, const char *flag, int negate, safe_str(Name(thing), tbuf1, &tp); safe_str(" - ", tbuf1, &tp); safe_str(f->name, tbuf1, &tp); + if (current) + safe_str(" (already)", tbuf1, &tp); safe_str(T(" set."), tbuf1, &tp); *tp = '\0'; notify(player, tbuf1); diff --git a/src/funcrypt.c b/src/funcrypt.c index 82e3280..5ec3bb1 100644 --- a/src/funcrypt.c +++ b/src/funcrypt.c @@ -40,7 +40,9 @@ static char *crunch_code(char *code); static char *crypt_code(char *code, char *text, int type); +#ifdef HAVE_SSL static void safe_hexchar(unsigned char c, char *buff, char **bp); +#endif /* HAVE_SSL */ static bool encode_base64 @@ -112,7 +114,7 @@ decode_base64(char *encoded, int len, char *buff, char **bp) BIO_free(b64); return false; } - len = BIO_set_close(bmem, BIO_NOCLOSE); + /* len = BIO_set_close(bmem, BIO_NOCLOSE); This makes valgrind report a memory leak. */ bio = BIO_push(b64, bmem); @@ -154,6 +156,7 @@ decode_base64(char *encoded, int len, char *buff, char **bp) } else if (dlen == 0) break; else { + BIO_free_all(bio); *bp = sbp; safe_str(T("#-1 CONVERSION ERROR"), buff, bp); return false; @@ -376,6 +379,7 @@ FUNCTION(fun_digest) #endif } +#ifdef HAVE_SSL static void safe_hexchar(unsigned char c, char *buff, char **bp) { @@ -389,3 +393,4 @@ safe_hexchar(unsigned char c, char *buff, char **bp) (*bp)++; } } +#endif /* HAVE_SSL */ diff --git a/src/function.c b/src/function.c index 3c8f856..070330c 100644 --- a/src/function.c +++ b/src/function.c @@ -33,11 +33,9 @@ static void func_hash_insert(const char *name, FUN *func); static int apply_restrictions(unsigned int result, const char *restriction); static char *build_function_report(dbref player, FUN *fp); -USERFN_ENTRY *userfn_tab; /**< Table of user-defined functions */ HASHTAB htab_function; /**< Function hash table */ HASHTAB htab_user_function; /**< User-defined function hash table */ slab *function_slab; /**< slab for 'struct fun' allocations */ -slab *userfun_slab; /**< slab for 'struct userfn_entry' allocations */ /* -------------------------------------------------------------------------* * Utilities. @@ -388,7 +386,7 @@ FUNTAB flist[] = { {"CONVUTCSECS", fun_convsecs, 1, 1, FN_REG}, {"CONVTIME", fun_convtime, 1, 1, FN_REG}, {"COR", fun_cor, 2, INT_MAX, FN_NOPARSE}, - {"CREATE", fun_create, 1, 2, FN_REG}, + {"CREATE", fun_create, 1, 3, FN_REG}, {"CSECS", fun_csecs, 1, 1, FN_REG}, {"CTIME", fun_ctime, 1, 2, FN_REG}, {"DEC", fun_dec, 1, 1, FN_REG}, @@ -608,7 +606,7 @@ FUNTAB flist[] = { {"OOREF", fun_ooref, 0, 0, FN_REG}, {"OWNER", fun_owner, 1, 1, FN_REG}, {"PARENT", fun_parent, 1, 2, FN_REG}, - {"PCREATE", fun_pcreate, 1, 2, FN_REG}, + {"PCREATE", fun_pcreate, 2, 3, FN_REG}, {"PEMIT", fun_pemit, 2, -2, FN_REG}, {"PGHASPOWER", fun_pghaspower, 3, 4, FN_REG}, {"PGPOWERS", fun_pgpowers, 2, 2, FN_REG}, @@ -955,7 +953,6 @@ init_func_hashtab(void) void function_init_postconfig(void) { - userfn_tab = mush_calloc(MAX_GLOBAL_FNS, sizeof(USERFN_ENTRY), "userfn_tab"); } /** Check permissions to run a function. @@ -1085,9 +1082,6 @@ strip_braces(const char *str) * User-defined global function handlers */ - -static size_t userfn_count = 0; - static int apply_restrictions(unsigned int result, const char *xres) { @@ -1229,8 +1223,7 @@ do_function_restrict(dbref player, const char *name, const char *restriction, safe_format(tbuf1, &bp, "%s %s - ", T("Builtin function"), fp->name); else safe_format(tbuf1, &bp, "%s #%d/%s - ", T("@function"), - userfn_tab[fp->where.offset].thing, - userfn_tab[fp->where.offset].name); + fp->where.ufun->thing, fp->where.ufun->name); if (fp->flags == flags) safe_str(T("Restrictions unchanged."), tbuf1, &bp); else @@ -1250,8 +1243,8 @@ func_comp(const void *s1, const void *s2) a = *(const FUN **) s1; b = *(const FUN **) s2; - da = userfn_tab[a->where.offset].thing; - db = userfn_tab[b->where.offset].thing; + da = a->where.ufun->thing; + db = b->where.ufun->thing; if (da == db) return strcmp(a->name, b->name); @@ -1280,6 +1273,7 @@ do_function(dbref player, char *name, char *argv[], int preserve) char *bp = tbuf1; dbref thing; FUN *fp; + size_t userfn_count = htab_user_function.entries; /* if no arguments, just give the list of user functions, by walking * the function hash table, and looking up all functions marked @@ -1310,8 +1304,7 @@ do_function(dbref player, char *name, char *argv[], int preserve) fp = funclist[n]; notify_format(player, "%-32s %6d %s", fp->name, - userfn_tab[fp->where.offset].thing, - userfn_tab[fp->where.offset].name); + fp->where.ufun->thing, fp->where.ufun->name); } mush_free(funclist, "function.fp.list"); } else { @@ -1375,10 +1368,6 @@ do_function(dbref player, char *name, char *argv[], int preserve) fp = func_hash_lookup(upcasestr(name)); if (!fp) { - if (userfn_count >= (size_t) MAX_GLOBAL_FNS) { - notify(player, T("Function table full.")); - return; - } if (argv[6] && *argv[6]) { notify(player, T("Expected between 1 and 5 arguments.")); return; @@ -1386,7 +1375,6 @@ do_function(dbref player, char *name, char *argv[], int preserve) /* a completely new entry. First, insert it into general hash table */ fp = slab_malloc(function_slab, NULL); fp->name = mush_strdup(name, "func_hash.name"); - fp->where.offset = userfn_count; if (argv[3] && *argv[3]) { fp->minargs = parse_integer(argv[3]); if (fp->minargs < 0) @@ -1413,11 +1401,9 @@ do_function(dbref player, char *name, char *argv[], int preserve) hashadd(name, fp, &htab_user_function); /* now add it to the user function table */ - userfn_tab[userfn_count].thing = thing; - userfn_tab[userfn_count].name = - mush_strdup(upcasestr(argv[2]), "userfn_tab.name"); - userfn_tab[userfn_count].fn = mush_strdup(name, "usrfn_tab.fn"); - userfn_count++; + fp->where.ufun = mush_malloc(sizeof(USERFN_ENTRY), "userfn"); + fp->where.ufun->thing = thing; + fp->where.ufun->name = mush_strdup(upcasestr(argv[2]), "userfn.name"); notify(player, T("Function added.")); return; @@ -1429,23 +1415,16 @@ do_function(dbref player, char *name, char *argv[], int preserve) return; } if (fp->flags & FN_BUILTIN) { /* Overriding a built in function */ - if (userfn_count >= (size_t) MAX_GLOBAL_FNS) { - notify(player, T("Function table full.")); - return; - } fp = slab_malloc(function_slab, NULL); fp->name = mush_strdup(name, "func_hash.name"); - fp->where.offset = userfn_count; + fp->where.ufun = mush_malloc(sizeof(USERFN_ENTRY), "userfn"); fp->flags = 0; - userfn_count++; hashadd(name, fp, &htab_user_function); } - userfn_tab[fp->where.offset].thing = thing; - if (userfn_tab[fp->where.offset].name) - mush_free((Malloc_t) userfn_tab[fp->where.offset].name, - "userfn_tab.name"); - userfn_tab[fp->where.offset].name = - mush_strdup(upcasestr(argv[2]), "userfn_tab.name"); + fp->where.ufun->thing = thing; + if (fp->where.ufun->name) + mush_free(fp->where.ufun->name, "userfn.name"); + fp->where.ufun->name = mush_strdup(upcasestr(argv[2]), "userfn.name"); if (argv[3] && *argv[3]) { fp->minargs = parse_integer(argv[3]); if (fp->minargs < 0) @@ -1480,26 +1459,12 @@ do_function(dbref player, char *name, char *argv[], int preserve) static void delete_function(void *data) { - size_t table_index, i; FUN *fp = data; - table_index = fp->where.offset; mush_free((void *) fp->name, "func_hash.name"); + mush_free(fp->where.ufun->name, "userfn.name"); + mush_free(fp->where.ufun, "userfn"); slab_free(function_slab, fp); - /* Fix up the user function table. Expensive, but how often will - * we need to delete an @function anyway? - */ - mush_free(userfn_tab[table_index].name, "userfn_tab.name"); - mush_free(userfn_tab[table_index].fn, "usrfn_tab.fn"); - userfn_count--; - for (i = table_index; i < userfn_count; i++) { - fp = (FUN *) hashfind(userfn_tab[i + 1].fn, &htab_user_function); - fp->where.offset = i; - userfn_tab[i].thing = userfn_tab[i + 1].thing; - userfn_tab[i].name = userfn_tab[i + 1].name; - userfn_tab[i].fn = userfn_tab[i + 1].fn; - } - } /** Restore an overridden built-in function. @@ -1582,7 +1547,7 @@ do_function_delete(dbref player, char *name) return; } - if (!controls(player, userfn_tab[fp->where.offset].thing)) { + if (!controls(player, fp->where.ufun->thing)) { notify(player, T("You can't delete that @function.")); return; } @@ -1776,12 +1741,9 @@ build_function_report(dbref player, FUN *fp) safe_format(buff, &bp, T("Flags : %s"), tbuf); safe_chr('\n', buff, &bp); - if (!(fp->flags & FN_BUILTIN) && Global_Funcs(player)) { - safe_format(buff, &bp, T("Location : #%d/%s"), - userfn_tab[fp->where.offset].thing, - userfn_tab[fp->where.offset].name); - safe_chr('\n', buff, &bp); - } + if (!(fp->flags & FN_BUILTIN) && Global_Funcs(player)) + safe_format(buff, &bp, T("Location : #%d/%s\n"), + fp->where.ufun->thing, fp->where.ufun->name); maxargs = abs(fp->maxargs); diff --git a/src/fundb.c b/src/fundb.c index 806a3f6..ac603cf 100644 --- a/src/fundb.c +++ b/src/fundb.c @@ -1182,7 +1182,8 @@ FUNCTION(fun_elock) it = match_thing(executor, args[0]); ltype = get_locktype(p); - if (!GoodObject(it) || (ltype == NULL) ||!Can_Read_Lock(executor, it, ltype)) { + if (!GoodObject(it) || !GoodObject(victim) + || (ltype == NULL) ||!Can_Read_Lock(executor, it, ltype)) { safe_str("#-1", buff, bp); return; } @@ -1518,8 +1519,10 @@ FUNCTION(fun_alias) dbref it; it = match_thing(executor, args[0]); - if (!GoodObject(it)) + if (!GoodObject(it)) { safe_str(T(e_notvis), buff, bp); + return; + } /* Support changing alias via function if side-effects are enabled */ if (nargs == 2) { @@ -1872,7 +1875,7 @@ FUNCTION(fun_create) cost = parse_integer(args[1]); else cost = OBJECT_COST; - safe_dbref(do_create(executor, args[0], cost), buff, bp); + safe_dbref(do_create(executor, args[0], cost, args[2]), buff, bp); } /* ARGSUSED */ @@ -1886,7 +1889,7 @@ FUNCTION(fun_pcreate) safe_str(T(e_perm), buff, bp); return; } - safe_dbref(do_pcreate(executor, args[0], args[1]), buff, bp); + safe_dbref(do_pcreate(executor, args[0], args[1], args[2]), buff, bp); } /* ARGSUSED */ diff --git a/src/fundiv.c b/src/fundiv.c index 67a7912..4b73a02 100644 --- a/src/fundiv.c +++ b/src/fundiv.c @@ -3,11 +3,8 @@ #include "copyrite.h" #include "config.h" -#ifdef I_STRING #include -#else #include -#endif #include "conf.h" #include "externs.h" #include "division.h" diff --git a/src/funlist.c b/src/funlist.c index 1197fef..9bfc132 100644 --- a/src/funlist.c +++ b/src/funlist.c @@ -8,6 +8,7 @@ #include "copyrite.h" #include "config.h" +#define _GNU_SOURCE #include #include #include "conf.h" @@ -663,7 +664,7 @@ FUNCTION(fun_shuffle) /* shuffle it */ for (i = 0; i < n; i++) { char *tmp; - j = get_random_long(i, n - 1); + j = get_random32(i, n - 1); tmp = words[j]; words[j] = words[i]; words[i] = tmp; @@ -1403,7 +1404,7 @@ FUNCTION(fun_randword) s = trim_space_sep(args[0], sep); word_count = do_wordcount(s, sep); - word_index = get_random_long(0, word_count - 1); + word_index = get_random32(0, word_count - 1); /* Go to the start of the token we're interested in. */ while (word_index && s) { diff --git a/src/funmath.c b/src/funmath.c index 82fe2aa..7405edc 100644 --- a/src/funmath.c +++ b/src/funmath.c @@ -13,6 +13,13 @@ #include #include #include + +#ifdef HAVE_SSE2 +#include +#endif +#ifdef HAVE_SSE3 +#include +#endif #include "conf.h" #include "externs.h" #include "sort.h" @@ -845,9 +852,43 @@ FUNCTION(fun_vcross) vec2[n] = parse_number(v2[n]); } + +#ifdef HAVE_SSE2 + { + __m128d xy1, xy2, xy3, xy4, z1, z2; + + xy1 = _mm_set_pd(vec1[2], vec1[1]); + xy2 = _mm_set_pd(vec2[0], vec2[2]); + xy3 = _mm_set_pd(vec2[2], vec2[1]); + xy4 = _mm_set_pd(vec1[0], vec1[2]); + z1 = _mm_set_pd(vec2[0], vec1[0]); + z2 = _mm_set_pd(vec1[1], vec2[1]); + + xy1 = _mm_mul_pd(xy1, xy2); + xy2 = _mm_mul_pd(xy3, xy4); + xy3 = _mm_sub_pd(xy1, xy2); + z1 = _mm_mul_pd(z1, z2); + +#ifdef HAVE_SSE3 + z1 = _mm_hsub_pd(z1, z2); + _mm_store_sd(cross + 2, z1); +#else + { + /* SSE2 version */ + double zsub[2] __attribute__ ((__aligned__(16))); + _mm_store_pd(zsub, z1); + cross[2] = zsub[0] - zsub[1]; + } +#endif + + _mm_store_pd(cross, xy3); + } +#else + /* Scalar version */ cross[0] = vec1[1] * vec2[2] - vec2[1] * vec1[2]; cross[1] = vec1[2] * vec2[0] - vec2[2] * vec1[0]; cross[2] = vec1[0] * vec2[1] - vec2[0] * vec1[1]; +#endif safe_number(cross[0], buff, bp); safe_chr(sep, buff, bp); @@ -1107,8 +1148,9 @@ FUNCTION(fun_ln) safe_number(log(num), buff, bp); } -#ifndef HAVE_LOG2 -static double +/* Cygwin has a log2 that configure doesn't detect. Macro, maybe? */ +#if !defined(HAVE_LOG2) && !defined(__CYGWIN__) +static inline double log2(double x) { return log(x) / log(2.0); @@ -1786,32 +1828,71 @@ FUNCTION(fun_lmath) mush_free(ptr, "string"); } -extern char from_base_64[256]; -extern char to_base_64[]; - -extern char from_base_36[256]; -extern char to_base_36[]; - +/* Walker probably needs to convert from_base_XX arrays to a form + suitable for putting in utils/gentables.c. Copy & paste is not it. ;) */ +signed char from_base_64[256] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, 62, -1, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, + -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, 63, + -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 +}; + +signed char to_base_64[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; + +signed char from_base_36[256] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 +}; +signed char to_base_36[] = "0123456789abcdefghijklmnopqrstuvwxyz"; + FUNCTION(fun_baseconv) { - long n; + unsigned long n; + int isnegative = 0; int m; - int from, to; + unsigned int from, to; char *ptr; char numbuff[BUFFER_LEN], *nbp; - /* Base 36 by default */ - char *frombase = from_base_36; - char *tobase = to_base_36; + /* Base 36 by default. */ + signed char *frombase = from_base_36; + signed char *tobase = to_base_36; if (!(is_integer(args[1]) && is_integer(args[2]))) { safe_str(T(e_ints), buff, bp); return; } - from = parse_integer(args[1]); - to = parse_integer(args[2]); + from = parse_uinteger(args[1]); + to = parse_uinteger(args[2]); if (from < 2 || from > 64) { safe_str(T("#-1 FROM BASE OUT OF RANGE"), buff, bp); @@ -1830,10 +1911,15 @@ FUNCTION(fun_baseconv) if (to > 36) { tobase = to_base_64; } - // Parse it. + + /* Parse it. */ ptr = trim_space_sep(args[0], ' '); n = 0; while (ptr && *ptr) { + if (*ptr == '-') { + isnegative = 1; + continue; + } n *= from; if (frombase[(unsigned char) *ptr] >= 0) { n += frombase[(unsigned char) *ptr]; @@ -1844,7 +1930,7 @@ FUNCTION(fun_baseconv) } } - // Handle the 0-case. (And quickly handle < to_base case, too!) + /* Handle the 0-case. (And quickly handle < to_base case, too!) */ if (n < to) { safe_chr(tobase[(unsigned char) n], buff, bp); return; @@ -1852,15 +1938,18 @@ FUNCTION(fun_baseconv) nbp = numbuff; - // This comes out backwards. + /* This comes out backwards. */ while (n > 0) { m = n % to; n = n / to; safe_chr(tobase[(unsigned char) m], numbuff, &nbp); } - // Reverse back onto buff. + /* Reverse back onto buff. */ nbp--; + if (isnegative) { + safe_chr('-', buff, bp); + } while (nbp >= numbuff) { safe_chr(*nbp, buff, bp); nbp--; diff --git a/src/funmisc.c b/src/funmisc.c index a971acb..1b4c886 100644 --- a/src/funmisc.c +++ b/src/funmisc.c @@ -331,7 +331,7 @@ FUNCTION(fun_rand) return; } - safe_integer(get_random_long(low, high), buff, bp); + safe_integer(get_random32(low, high), buff, bp); } /* ARGSUSED */ @@ -362,11 +362,11 @@ FUNCTION(fun_die) first = 0; else safe_chr(' ', buff, bp); - safe_uinteger(get_random_long(1, die), buff, bp); + safe_uinteger(get_random32(1, die), buff, bp); } } else { for (count = 0; count < n; count++) - total += get_random_long(1, die); + total += get_random32(1, die); safe_uinteger(total, buff, bp); } @@ -578,12 +578,7 @@ FUNCTION(fun_restarts) safe_integer(globals.reboot_count, buff, bp); } -/* Data for soundex functions */ -static char soundex_val[26] = { - 0, 1, 2, 3, 0, 1, 2, 0, 0, - 2, 2, 4, 5, 5, 0, 1, 2, 6, - 2, 3, 0, 1, 0, 2, 0, 2 -}; +extern char soundex_val[UCHAR_MAX + 1]; /* The actual soundex routine */ static char * @@ -593,28 +588,27 @@ soundex(str) static char tbuf1[BUFFER_LEN]; char *p, *q; - tbuf1[0] = '\0'; - tbuf1[1] = '\0'; - tbuf1[2] = '\0'; - tbuf1[3] = '\0'; + q = remove_markup(str, NULL); + memset(tbuf1, '\0', 4); p = tbuf1; - q = upcasestr(remove_markup(str, NULL)); + /* First character is just copied */ - *p = *q++; + *p = UPCASE(*q); + q++; /* Special case for PH->F */ - if ((*p == 'P') && *q && (*q == 'H')) { + if ((UPCASE(*p) == 'P') && *q && (UPCASE(*q) == 'H')) { *p = 'F'; q++; } p++; - /* Convert letters to soundex values, squash duplicates */ + /* Convert letters to soundex values, squash duplicates, skip accents and other non-ascii characters */ while (*q) { if (!isalpha((unsigned char) *q) || (unsigned char) *q > 127) { q++; continue; } - *p = soundex_val[*q++ - 'A'] + '0'; + *p = soundex_val[(unsigned char) *q++]; if (*p != *(p - 1)) p++; } diff --git a/src/funstr.c b/src/funstr.c index 49eccc0..ba6ba26 100644 --- a/src/funstr.c +++ b/src/funstr.c @@ -588,6 +588,7 @@ FUNCTION(fun_lpos) FUNCTION(fun_strmatch) { char tbuf[BUFFER_LEN]; + char pattern[BUFFER_LEN]; char *ret[36]; char *t; size_t len; @@ -603,8 +604,10 @@ FUNCTION(fun_strmatch) t = remove_markup(args[0], &len); memcpy(tbuf, t, len); + t = remove_markup(args[1], &len); + memcpy(pattern, t, len); memset(ret, 0, 36); - matches = wild_match_case_r(remove_markup(args[1], NULL), tbuf, 0, ret, + matches = wild_match_case_r(pattern, tbuf, 0, ret, NUMQ, match_space, match_space_len); safe_boolean(matches, buff, bp); @@ -2005,7 +2008,7 @@ FUNCTION(fun_speak) const char *speaker_name; char *open, *close; char *start, *end = NULL; - bool transform = 0, null = 0, say = 0; + bool transform = 0, null = 0, say = 0, starting_fragment = 0; char *wenv[3]; int funccount; int fragment = 0; @@ -2150,6 +2153,7 @@ FUNCTION(fun_speak) } else { /* We're in say mode and the first char isn't open, start there */ start = string; + starting_fragment = 1; } funccount = pe_info->fun_invocations; @@ -2176,8 +2180,11 @@ FUNCTION(fun_speak) (pe_info->fun_invocations == funccount)) break; if (end && *end) { - if (say) - safe_str(close, buff, bp); + if (!starting_fragment) { + if (say) + safe_str(close, buff, bp); + starting_fragment = 0; + } } if (!end || !*end) break; @@ -2187,6 +2194,7 @@ FUNCTION(fun_speak) if (start && *start && (start - end > (ptrdiff_t) strlen(open))) safe_str(chopstr(end, start - end + 1), buff, bp); start += strlen(open); + end = NULL; } else { /* No more opens, so we're done, and end has the rest */ break; diff --git a/src/game.c b/src/game.c index 55015db..7a2c0a1 100644 --- a/src/game.c +++ b/src/game.c @@ -106,9 +106,8 @@ extern void initialize_mt(void); extern const unsigned char *tables; extern void conf_default_set(void); static bool dump_database_internal(void); -static FILE *db_open(const char *filename); -static FILE *db_open_write(const char *filename); -static void db_close(FILE * f); +static PENNFILE *db_open(const char *); +static PENNFILE *db_open_write(const char *); static int fail_commands(dbref player); void do_readcache(dbref player); int check_alias(const char *command, const char *list); @@ -326,7 +325,7 @@ dump_database_internal(void) char realdumpfile[2048]; char realtmpfl[2048]; char tmpfl[2048]; - FILE *f = NULL; + PENNFILE *f = NULL; struct module_entry_t *m; void (*handle)(); @@ -342,7 +341,7 @@ dump_database_internal(void) compression slave. Boo! */ do_rawlog(LT_ERR, T("ERROR! Database save failed.")); if(f) - db_close(f); + penn_fclose(f); #ifndef PROFILING #ifdef HAS_ITIMER install_sig_handler(SIGPROF, signal_cpu_limit); @@ -367,7 +366,7 @@ dump_database_internal(void) if((f = db_open_write(tmpfl)) != NULL) { use_flagfile = 1; db_write_flag_db(f); - db_close(f); + penn_fclose(f); #ifdef WIN32 unlink(realdumpfile); #endif @@ -401,7 +400,7 @@ dump_database_internal(void) db_paranoid_write(f, 1); break; } - db_close(f); + penn_fclose(f); #ifdef WIN32 /* Win32 systems can't rename over an existing file, so unlink first */ unlink(realdumpfile); @@ -421,7 +420,7 @@ dump_database_internal(void) if (mdb_top >= 0) { if ((f = db_open_write(tmpfl)) != NULL) { dump_mail(f); - db_close(f); + penn_fclose(f); #ifdef WIN32 unlink(realdumpfile); #endif @@ -441,7 +440,7 @@ dump_database_internal(void) sprintf(realtmpfl, "%s%s", tmpfl, options.compresssuff); if ((f = db_open_write(tmpfl)) != NULL) { save_chatdb(f); - db_close(f); + penn_fclose(f); #ifdef WIN32 unlink(realdumpfile); #endif @@ -477,7 +476,7 @@ void mush_panic(const char *message) { const char *panicfile = options.crash_db; - FILE *f = NULL; + PENNFILE *f = NULL; static int already_panicking = 0; if (already_panicking) { @@ -506,7 +505,7 @@ mush_panic(const char *message) do_rawlog(LT_ERR, T("CANNOT DUMP PANIC DB. OOPS.")); _exit(134); } else { - if ((f = fopen(panicfile, FOPEN_WRITE)) == NULL) { + if ((f = penn_fopen(panicfile, FOPEN_WRITE)) == NULL) { do_rawlog(LT_ERR, T("CANNOT OPEN PANIC FILE, YOU LOSE")); _exit(135); } else { @@ -518,7 +517,7 @@ mush_panic(const char *message) #ifdef CHAT_SYSTEM save_chatdb(f); #endif /* CHAT_SYSTEM */ - fclose(f); + penn_fclose(f); do_rawlog(LT_ERR, T("DUMPING: %s (done)"), panicfile); } } @@ -666,7 +665,7 @@ fork_and_dump(int forking) chunk_fork_done(); #endif if (!nofork) { - _exit(status); /* !!! */ + _exit(status ? 0 : 1); /* d_d_i() returns true on success but exit code should be 0 on success */ } else { reserve_fd(); if (status && DUMP_NOFORK_COMPLETE && *DUMP_NOFORK_COMPLETE) @@ -885,7 +884,7 @@ extern int dbline; int init_game_dbs(void) { - FILE *f; + PENNFILE *f; int c; const char *infile, *outfile; #ifdef USE_MAILER @@ -919,7 +918,7 @@ init_game_dbs(void) if(load_flag_db(f) != 0) use_flagfile = 0; do_rawlog(LT_ERR, "LOADING: %s(done)", flag_file); - db_close(f); + penn_fclose(f); } } else use_flagfile = 0; @@ -935,7 +934,7 @@ init_game_dbs(void) return 0; } - c = getc(f); + c = penn_fgetc(f); if (c == EOF) { do_rawlog(LT_ERR, "Couldn't read %s! Creating minimal world.", infile); init_compress(NULL); @@ -943,7 +942,7 @@ init_game_dbs(void) return 0; } - ungetc(c, f); + penn_ungetc(c, f); if (setjmp(db_err) == 0) { /* ok, read it in */ @@ -955,7 +954,7 @@ init_game_dbs(void) do_rawlog(LT_ERR, "ANALYZING: %s (done)", infile); /* everything ok */ - db_close(f); + penn_fclose(f); f = db_open(infile); if (!f) @@ -966,7 +965,7 @@ init_game_dbs(void) dbline = 0; if (db_read(f) < 0) { do_rawlog(LT_ERR, "ERROR LOADING %s", infile); - db_close(f); + penn_fclose(f); return -1; } do_rawlog(LT_ERR, "LOADING: %s (done)", infile); @@ -975,10 +974,10 @@ init_game_dbs(void) * format db, with everything shoved together. In that case, * don't close the file */ - panicdb = ((globals.indb_flags & DBF_PANIC) && !feof(f)); + panicdb = ((globals.indb_flags & DBF_PANIC) && !penn_feof(f)); if (!panicdb) - db_close(f); + penn_fclose(f); /* complain about bad config options */ if (!GoodObject(PLAYER_START) || (!IsRoom(PLAYER_START))) @@ -1004,11 +1003,11 @@ init_game_dbs(void) do_rawlog(LT_ERR, T("LOADING: Trying to get mail from %s"), infile); if (load_mail(f) <= 0) { do_rawlog(LT_ERR, T("FAILED: Reverting to normal maildb")); - db_close(f); + penn_fclose(f); panicdb = 0; } } else /* Close the panicdb file handle */ - db_close(f); + penn_fclose(f); if (!panicdb) { f = db_open(mailfile); @@ -1018,7 +1017,7 @@ init_game_dbs(void) dbline = 0; load_mail(f); do_rawlog(LT_ERR, "LOADING: %s (done)", mailfile); - db_close(f); + penn_fclose(f); } } #endif /* USE_MAILER */ @@ -1030,7 +1029,7 @@ init_game_dbs(void) do_rawlog(LT_ERR, T("LOADING: Trying to get chat from %s"), infile); if (load_chatdb(f) <= 0) { do_rawlog(LT_ERR, T("FAILED: Reverting to normal chatdb")); - db_close(f); + penn_fclose(f); panicdb = 0; } } @@ -1046,7 +1045,7 @@ init_game_dbs(void) do_rawlog(LT_ERR, "ERROR LOADING %s", options.chatdb); return -1; } - db_close(f); + penn_fclose(f); } } #endif /* CHAT_SYSTEM */ @@ -1074,7 +1073,7 @@ do_readcache(dbref player) /** Check each attribute on each object in x for a $command matching cptr */ #define list_match(x) list_check(x, player, '$', ':', cptr, 0) /** Check each attribute on x for a $command matching cptr */ -#define cmd_match(x) atr_comm_match(x, player, '$', ':', cptr, 0, NULL, NULL, &errdb) +#define cmd_match(x) atr_comm_match(x, player, '$', ':', cptr, 0, 1, NULL, NULL, &errdb) #define MAYBE_ADD_ERRDB(errdb) \ do { \ if (GoodObject(errdb) && errdblist) { \ @@ -1446,7 +1445,7 @@ list_check(dbref thing, dbref player, char type, char end, char *str, while (thing != NOTHING) { if (atr_comm_match - (thing, player, type, end, str, just_match, NULL, NULL, &errdb)) + (thing, player, type, end, str, just_match, 1, NULL, NULL, &errdb)) match = 1; else { MAYBE_ADD_ERRDB(errdb); @@ -1648,7 +1647,7 @@ bind_and_queue(dbref player, dbref cause, char *action, /** Would the scan command find an matching attribute on x for player p? */ #define ScanFind(p,x) \ (Can_Examine(p,x) && \ - ((num = atr_comm_match(x, p, '$', ':', command, 1, atrname, &ptr, NULL)) != 0)) + ((num = atr_comm_match(x, p, '$', ':', command, 1, 1, atrname, &ptr, NULL)) != 0)) /** Scan for matches of $commands. * This function scans for possible matches of user-def'd commands from the @@ -2305,44 +2304,80 @@ do_uptime(dbref player) } -/* Open a db file, which may be compressed, and return a file pointer */ -static FILE * -db_open(const char *filename) +/* Open a db file, which may be compressed, and return a file pointer. These probably should be moved into db.c or + a new dbio.c */ +static PENNFILE * +db_open(const char *fname) { - FILE *f; + PENNFILE *pf; + char filename[BUFFER_LEN]; + + snprintf(filename, sizeof filename, "%s%s", fname, options.compresssuff); + + pf = mush_malloc(sizeof *pf, "pennfile"); + +#ifdef HAVE_LIBZ + if (*options.uncompressprog && strcmp(options.uncompressprog, "gunzip") == 0) { + pf->type = PFT_GZFILE; + pf->handle.g = gzopen(filename, "rb"); + if (!pf->handle.g) { + mush_free(pf, "pennfile"); + longjmp(db_err, 1); + } + return pf; + } +#endif + #ifndef WIN32 - if (options.uncompressprog && *options.uncompressprog) { + if (*options.uncompressprog) { + pf->type = PFT_PIPE; /* We do this because on some machines (SGI Irix, for example), * the popen will not return NULL if the mailfile isn't there. */ - f = fopen(tprintf("%s%s", filename, options.compresssuff), "r"); - if (f) { - fclose(f); - f = + + if (access(filename, R_OK) == 0) { + pf->handle.f = #ifdef __LCC__ (FILE *) #endif - popen(tprintf - ("%s < %s%s", options.uncompressprog, filename, - options.compresssuff), "r"); + popen(tprintf("%s < '%s'", options.uncompressprog, filename), "r"); /* Force the pipe to be fully buffered */ - if (f) - setvbuf(f, NULL, _IOFBF, BUFSIZ); + if (pf->handle.f) { + setvbuf(pf->handle.f, NULL, _IOFBF, BUFSIZ); + } else + do_rawlog(LT_ERR, "Unable to run '%s < %s': %s", + options.uncompressprog, filename, strerror(errno)); + } else { + mush_free(pf, "pennfile"); + longjmp(db_err, 1); } } else #endif /* WIN32 */ { - f = fopen(filename, FOPEN_READ); + pf->type = PFT_FILE; + pf->handle.f = fopen(filename, FOPEN_READ); +#ifdef HAVE_POSIX_FADVISE + if (pf->handle.f) + posix_fadvise(fileno(pf->handle.f), 0, 0, POSIX_FADV_SEQUENTIAL); +#endif + } - return f; + if (!pf->handle.f) { + mush_free(pf, "pennfile"); + longjmp(db_err, 1); + } + return pf; } /* Open a file or pipe (if compressing) for writing */ -static FILE * -db_open_write(const char *filename) +static PENNFILE * +db_open_write(const char *fname) { - FILE *f; + PENNFILE *pf; char workdir[BUFFER_LEN]; + char filename[BUFFER_LEN]; + + snprintf(filename, sizeof filename, "%s%s", fname, options.compresssuff); /* Be safe in case our game directory was removed and restored, * in which case our inode is screwy @@ -2363,43 +2398,50 @@ db_open_write(const char *filename) "getcwd failed during db_open_write, errno %d (%s)\n", errno, strerror(errno)); } + + pf = mush_malloc(sizeof *pf, "pennfile"); + +#ifdef HAVE_LIBZ + if (*options.compressprog && strcmp(options.compressprog, "gzip") == 0) { + pf->type = PFT_GZFILE; + pf->handle.g = gzopen(filename, "wb"); + if (!pf->handle.g) { + mush_free(pf, "pennfile"); + longjmp(db_err, 1); + } + return pf; + } +#endif + #ifndef WIN32 - if (options.compressprog && *options.compressprog) { - f = + if (*options.compressprog) { + pf->type = PFT_PIPE; + pf->handle.f = #ifdef __LCC__ (FILE *) #endif - popen(tprintf - ("%s >%s%s", options.compressprog, filename, - options.compresssuff), "w"); + popen(tprintf("%s > '%s'", options.compressprog, filename), "w"); /* Force the pipe to be fully buffered */ - if (f) - setvbuf(f, NULL, _IOFBF, BUFSIZ); + if (pf->handle.f) { + setvbuf(pf->handle.f, NULL, _IOFBF, BUFSIZ); + } else + do_rawlog(LT_ERR, "Unable to run '%s > %s': %s", + options.compressprog, filename, strerror(errno)); + } else #endif /* WIN32 */ { - f = fopen(filename, FOPEN_WRITE); + pf->type = PFT_FILE; + pf->handle.f = fopen(filename, "wb"); } - if (!f) + if (!pf->handle.f) { + mush_free(pf, "pennfile"); longjmp(db_err, 1); - return f; -} - - -/* Close a db file, which may really be a pipe */ -static void -db_close(FILE * f) -{ -#ifndef WIN32 - if (options.compressprog && *options.compressprog) { - pclose(f); - } else -#endif /* WIN32 */ - { - fclose(f); } + return pf; } + /** List various goodies. * \verbatim * This function implements @list. diff --git a/src/help.c b/src/help.c index 30abcd3..efc269d 100644 --- a/src/help.c +++ b/src/help.c @@ -11,6 +11,7 @@ #include #include #include +#include #include "conf.h" #include "externs.h" #include "boolexp.h" @@ -383,6 +384,10 @@ help_build_index(help_file *h, int restricted) in_topic = 0; +#ifdef HAVE_POSIX_FADVISE + posix_fadvise(fileno(rfp), 0, 0, POSIX_FADV_SEQUENTIAL); +#endif + while (fgets(line, LINE_SIZE, rfp) != NULL) { ++lineno; if (ntopics == 0) { diff --git a/src/htab.c b/src/htab.c index 4298380..3f74995 100644 --- a/src/htab.c +++ b/src/htab.c @@ -48,6 +48,9 @@ #ifdef HAVE_STDINT_H #include #endif +#ifdef HAS_OPENSSL +#include +#endif #include "conf.h" #include "externs.h" @@ -263,7 +266,7 @@ penn_hash(const char *key, int len) return hash; } -typedef uint32_t(*hash_func) (const char *, int); +typedef uint32_t (*hash_func) (const char *, int); hash_func hash_functions[] = { hsieh_hash, @@ -279,11 +282,39 @@ hash_func hash_functions[] = { enum { NHASH_TRIES = 3, NHASH_MOD = 8 }; /* Return the next prime number after its arg */ -static int -next_prime_after(int val) +static unsigned int +next_prime_after(unsigned int val) { +#ifdef HAS_OPENSSL + /* Calculate primes on the fly using OpenSSL. Takes up less space + than using a table, deals better with pathologically large tables. */ + static BIGNUM *p = NULL; + static BN_CTX *ctx = NULL; + + if (!ctx) + ctx = BN_CTX_new(); + if (!p) + p = BN_new(); + + /* Make sure we only try odd numbers; evens can't be primes. */ + if (val & 0x1) + val += 2; + else + val += 1; + + while (1) { + BN_set_word(p, val); + if (BN_is_prime(p, BN_prime_checks, NULL, ctx, NULL) > 0) + break; + val += 2; + } + + return val; + +#else + /* For non-SSL systems; use a static table of primes that should be more than big enough. */ /* Most of the first thousand primes */ - static int primes[] = { + static unsigned int primes[] = { 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, @@ -382,6 +413,7 @@ next_prime_after(int val) return val + 1; else return primes[n]; +#endif } /** Initialize a hashtable. @@ -460,7 +492,7 @@ hash_insert(HASHTAB *htab, const char *key, void *data) } /* None. Use a random func and bump the existing element */ - n = htab->hashfunc_offset + get_random_long(0, NHASH_TRIES - 1); + n = htab->hashfunc_offset + get_random32(0, NHASH_TRIES - 1); n %= NHASH_MOD; hval = (hash_functions[n]) (bump.key, keylen) % htab->hashsize; temp = htab->buckets[hval]; diff --git a/src/ident.c b/src/ident.c index ef451c2..4fa38d4 100644 --- a/src/ident.c +++ b/src/ident.c @@ -20,7 +20,6 @@ #ifdef I_SYS_TYPES #include #endif -#include #ifdef I_SYS_TIME #include #ifdef TIME_WITH_SYS_TIME diff --git a/src/lock.c b/src/lock.c index 10bd284..552443e 100644 --- a/src/lock.c +++ b/src/lock.c @@ -43,7 +43,6 @@ #include "match.h" #include "log.h" #include "flags.h" -#include "dbdefs.h" #include "mymalloc.h" #include "strtree.h" #include "privtab.h" diff --git a/src/log.c b/src/log.c index abfd7f8..e30c09b 100644 --- a/src/log.c +++ b/src/log.c @@ -24,7 +24,6 @@ #include #endif #endif -#include #ifdef I_SYS_TYPES #include #endif diff --git a/src/look.c b/src/look.c index 56eb82f..bc2898d 100644 --- a/src/look.c +++ b/src/look.c @@ -8,7 +8,7 @@ #include "config.h" #include "copyrite.h" - +#define _GNU_SOURCE #include #include diff --git a/src/malias.c b/src/malias.c index a019a30..2f4fff3 100644 --- a/src/malias.c +++ b/src/malias.c @@ -988,7 +988,7 @@ get_malias(dbref player, char *alias) * \param fp file pointer to read from. */ void -load_malias(FILE * fp) +load_malias(PENNFILE *fp) { int i, j; char buffer[BUFFER_LEN]; @@ -1025,7 +1025,7 @@ load_malias(FILE * fp) m->members = NULL; } } - s = fgets(buffer, sizeof(buffer), fp); + s = penn_fgets(buffer, sizeof(buffer), fp); if (!s || strcmp(buffer, "\"*** End of MALIAS ***\"\n") != 0) { do_rawlog(LT_ERR, T("MAIL: Error reading MALIAS list")); @@ -1036,7 +1036,7 @@ load_malias(FILE * fp) * \param fp file pointer to write to. */ void -save_malias(FILE * fp) +save_malias(PENNFILE *fp) { int i, j; struct mail_alias *m; diff --git a/src/markup.c b/src/markup.c index 0dead9f..9710c24 100644 --- a/src/markup.c +++ b/src/markup.c @@ -1587,7 +1587,7 @@ scramble_ansi_string(ansi_string *as) pos[i] = i; for (i = 0; i < as->len; i++) { - j = get_random_long(0, as->len - 1); + j = get_random32(0, as->len - 1); k = pos[i]; pos[i] = pos[j]; pos[j] = k; diff --git a/src/match.c b/src/match.c index 58b66e8..08801c6 100644 --- a/src/match.c +++ b/src/match.c @@ -240,8 +240,10 @@ match_result_internal(dbref who, const char *xname, int type, long flags) sname = name = mush_strdup(xname, "mri.string"); - /* Check for adjective phrases */ - matchnum = parse_english(&name, &flags); + if (flags & MAT_ENGLISH) { + /* Check for adjective phrases */ + matchnum = parse_english(&name, &flags); + } /* Perform matching. We've already had flags restricted by any * adjective phrases. If matchnum is set, collect the matchnum'th diff --git a/src/mymalloc.c b/src/mymalloc.c index 8ded5e2..4b5481e 100644 --- a/src/mymalloc.c +++ b/src/mymalloc.c @@ -32,6 +32,8 @@ #include #include #include +#include +#include #ifdef HAVE_UNISTD_H #include #endif @@ -46,16 +48,6 @@ #include "getpgsiz.h" #include "mymalloc.h" -/* An undefined or illegal MALLOC_PACKAGE is treated as system - * malloc, because we're such nice forgiving people - */ -#if (MALLOC_PACKAGE == 1) -#include "csrimalloc.c" -#elif (MALLOC_PACKAGE == 2) -#include "csrimalloc.c" -#endif - - /** A malloc wrapper that tracks type of allocation. * This should be used in preference to malloc() when possible, * to enable memory leak tracing with MEM_CHECK. @@ -256,22 +248,24 @@ static struct slab_page * slab_alloc_page(struct slab *sl) { struct slab_page *sp; - uint8_t *page; + uint8_t *page = NULL; int n; + int pgsize; -#if defined(HAVE_VALLOC) && MALLOC_TYPE == 0 - /* valloc() allocates on a page boundry. Many malloc()s do also, - but prefer this in case of one that implements valloc() without - malloc() having the same behavior for chunks the size of a page. + pgsize = getpagesize(); - TODO: Consider using mmap() or /dev/null instead, and adding an - access-pattern option that uses madvise() to give usage hints to - the VM system. That might only do any good on multi-page allocations, - though. +#ifdef HAVE_POSIX_MEMALIGN + /* Used to use valloc() here, but on some systems, memory returned by + valloc() can't be passed to free(). Those same systems probably won't have + posix_memalign. Deal. */ - page = valloc(getpagesize()); + if (posix_memalign((void **) &page, pgsize, pgsize) < 0) { + do_rawlog(LT_ERR, "Unable to allocate %d bytes via posix_memalign: %s", + pgsize, strerror(errno)); + page = malloc(pgsize); + } #else - page = malloc(getpagesize()); + page = malloc(pgsize); #endif sp = (struct slab_page *) page; @@ -551,7 +545,7 @@ slab_describe(dbref player, slab *sl) extern slab *attrib_slab, *lock_slab, *boolexp_slab, *bvm_asmnode_slab, *bvm_strnode_slab, *flag_slab, *player_dbref_slab, *command_slab, *mail_slab, - *bque_slab, *text_block_slab, *function_slab, *memcheck_slab, *intmap_slab; + *text_block_slab, *function_slab, *memcheck_slab, *intmap_slab; #ifdef CHAT_SYSTEM extern slab *chanuser_slab, *chanlist_slab, *channel_slab; #endif @@ -569,7 +563,6 @@ do_list_allocations(dbref player) return; } slab_describe(player, attrib_slab); - slab_describe(player, bque_slab); #ifdef DEBUG /* These should always be 0. No need to display them most of the time. */ diff --git a/src/myrlimit.c b/src/myrlimit.c index 8de95d1..10727e6 100644 --- a/src/myrlimit.c +++ b/src/myrlimit.c @@ -13,9 +13,6 @@ #include #include -#ifdef I_SYS_TYPES -#include -#endif #ifdef WIN32 #define FD_SETSIZE 256 #include diff --git a/src/myssl.c b/src/myssl.c index 068a782..4f96c20 100644 --- a/src/myssl.c +++ b/src/myssl.c @@ -105,8 +105,6 @@ static DH *get_dh1024(void); static BIO *bio_err = NULL; static SSL_CTX *ctx = NULL; -uint32_t genrand_int32(void); - /** Initialize the SSL context. * \return pointer to SSL context object. */ @@ -135,7 +133,7 @@ ssl_init(void) int n; for (n = 0; n < 4; n++) - gibberish[n] = genrand_int32(); + gibberish[n] = gen_rand32(); RAND_seed(gibberish, sizeof gibberish); diff --git a/src/notify.c b/src/notify.c index 92e16ce..487d444 100644 --- a/src/notify.c +++ b/src/notify.c @@ -957,7 +957,7 @@ notify_anything_loc(dbref speaker, na_lookup func, && eval_lock(speaker, target, Listen_Lock) ) atr_comm_match(target, speaker, '^', ':', - (char *) notify_makestring(msgbuf, messages, NA_ASCII), 0, + (char *) notify_makestring(msgbuf, messages, NA_ASCII), 0, 1, NULL, NULL, NULL); /* If object is flagged AUDIBLE and has a @FORWARDLIST, send diff --git a/src/parse.c b/src/parse.c index 022ea95..6b25ca1 100644 --- a/src/parse.c +++ b/src/parse.c @@ -1516,18 +1516,18 @@ process_expression(char *buff, char **bp, char const **str, ATTR *attrib; global_fun_invocations++; pe_info->fun_invocations++; - thing = userfn_tab[fp->where.offset].thing; - attrib = atr_get(thing, userfn_tab[fp->where.offset].name); + thing = fp->where.ufun->thing; + attrib = atr_get(thing, fp->where.ufun->name); if (!attrib) { do_rawlog(LT_ERR, T("ERROR: @function (%s) without attribute (#%d/%s)"), - fp->name, thing, userfn_tab[fp->where.offset].name); + fp->name, thing, fp->where.ufun->name); safe_str("#-1 @FUNCTION (", buff, bp); safe_str(fp->name, buff, bp); safe_str(") MISSING ATTRIBUTE (", buff, bp); safe_dbref(thing, buff, bp); safe_chr('/', buff, bp); - safe_str(userfn_tab[fp->where.offset].name, buff, bp); + safe_str(fp->where.ufun->name, buff, bp); safe_chr(')', buff, bp); } else { char *preserve[NUMQ]; diff --git a/src/pcre.c b/src/pcre.c index db6a684..f9d5f23 100644 --- a/src/pcre.c +++ b/src/pcre.c @@ -1255,6 +1255,8 @@ int + + pcre_get_substring_list(const char *subject, int *ovector, int stringcount, const char ***listptr); @@ -1343,6 +1345,8 @@ int + + pcre_get_substring(const char *subject, int *ovector, int stringcount, int stringnumber, const char **stringptr); @@ -1398,6 +1402,8 @@ int + + pcre_get_named_substring(const pcre * code, const char *subject, int *ovector, int stringcount, const char *stringname, const char **stringptr); @@ -2283,6 +2289,8 @@ static BOOL + + compile_regex(int, int, int *, uschar **, const uschar **, int *, BOOL, int, int *, int *, branch_chain *, compile_data *); diff --git a/src/player.c b/src/player.c index e263919..5fcd58b 100644 --- a/src/player.c +++ b/src/player.c @@ -56,13 +56,13 @@ extern struct module_entry_t *module_list; dbref email_register_player (const char *name, const char *email, const char *host, const char *ip); static dbref make_player - (const char *name, const char *password, const char *host, const char *ip); -static dbref create_guest(const char *host, const char *ip); -void do_password - (dbref player, dbref cause, const char *old, const char *newobj); - -static const char pword_attr[] = "XYXXY"; - + (const char *name, const char *password, const char *host, const char *ip, + dbref try_dbref); +void do_password(dbref player, dbref cause, const char *old, + const char *newobj); + static const char pword_attr[] = "XYXXY"; +dbref create_guest(const char *host, const char *ip); + extern struct db_stat_info current_state; /** Check a player's password against a given string. @@ -221,7 +221,7 @@ dbref create_guest(const char *host, const char *ip) { do_log(LT_CONN, 0, 0, T("Failed creation (no db space) from %s"), host); return NOTHING; } - gst_id = make_player(guest_name, "", host, ip); + gst_id = make_player(guest_name, "", host, ip, NOTHING); } else { /* Reset Guest */ object_flag_type flags; flags = string_to_bits("FLAG", options.player_flags); @@ -244,12 +244,13 @@ dbref create_guest(const char *host, const char *ip) { * \param password initial password of created player. * \param host host from which creation is attempted. * \param ip ip address from which creation is attempted. + * \param try_dbref NOTHING or dbref of garbage object to use. * \return dbref of created player, NOTHING if bad name, AMBIGUOUS if bad * password. */ dbref create_player(const char *name, const char *password, const char *host, - const char *ip) + const char *ip, dbref try_dbref) { dbref player; if (!ok_player_name(name, NOTHING, NOTHING)) { @@ -266,7 +267,7 @@ create_player(const char *name, const char *password, const char *host, return NOTHING; } /* else he doesn't already exist, create him */ - player = make_player(name, password, host, ip); + player = make_player(name, password, host, ip, try_dbref); SLEVEL(player) = LEVEL_UNREGISTERED; powergroup_db_set(NOTHING, player, PLAYER_DEF_POWERGROUP, 1); return player; @@ -356,9 +357,9 @@ email_register_player(const char *name, const char *email, const char *host, } /* Come up with a random password of length 7-12 chars */ - len = get_random_long(7, 12); + len = get_random32(7, 12); for (i = 0; i < len; i++) - passwd[i] = elems[get_random_long(0, NELEMS - 1)]; + passwd[i] = elems[get_random32(0, NELEMS - 1)]; passwd[len] = '\0'; /* If we've made it here, we can send the email and create the @@ -395,7 +396,7 @@ email_register_player(const char *name, const char *email, const char *host, pclose(fp); reserve_fd(); /* Ok, all's well, make a player */ - player = make_player(name, passwd, host, ip); + player = make_player(name, passwd, host, ip, NOTHING); (void) atr_add(player, "REGISTERED_EMAIL", email, GOD, 0); SLEVEL(player) = LEVEL_UNREGISTERED; powergroup_db_set(NOTHING, player, PLAYER_DEF_POWERGROUP, 1); @@ -415,7 +416,7 @@ email_register_player(const char *name, const char *email, const char *host, static dbref make_player(const char *name, const char *password, const char *host, - const char *ip) + const char *ip, dbref try_dbref) { dbref player; @@ -424,6 +425,11 @@ make_player(const char *name, const char *password, const char *host, struct module_entry_t *m; void (*handle)(dbref player); + if (try_dbref != NOTHING && GoodObject(try_dbref) && IsGarbage(try_dbref)) { + if (!make_first_free(try_dbref)) + return NOTHING; + } + player = new_object(); /* initialize everything */ diff --git a/src/sort.c b/src/sort.c index eaefc5b..d686831 100644 --- a/src/sort.c +++ b/src/sort.c @@ -6,6 +6,7 @@ #include "config.h" #include +#include #include #include "conf.h" #include "externs.h" @@ -172,7 +173,7 @@ loop: /* Pick something at random at swap it into the leftmost slot */ /* This is the pivot, we'll put it back in the right spot later */ - i = get_random_long(left, right); + i = get_random32(left, right); tmp = array[i]; array[i] = array[left]; array[left] = tmp; @@ -246,8 +247,6 @@ struct sort_record { dbref player __attribute__ ((__unused__)), \ char *sortflags __attribute__ ((__unused__))) - - GENRECORD(gen_alphanum) { size_t len; @@ -260,6 +259,91 @@ GENRECORD(gen_alphanum) } } +#define RealGoodObject(x) (GoodObject(x) && !IsGarbage(x)) + +GENRECORD(gen_magic) +{ + static char buff[BUFFER_LEN]; + char *bp = buff; + char *s = rec->val; + int intval; + int numdigits; + dbref victim; + + while (s && *s) { + switch (*s) { + case ESC_CHAR: + while (*s && *s != 'm') + s++; + break; + case TAG_START: + while (*s && *s != TAG_END) + s++; + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + intval = 0; + while (*s && isdigit(*s)) { + intval *= 10; + intval += *s - '0'; + s++; + } + safe_format(buff, &bp, "%.20d", intval); + if (*s == '.') { + s++; + if (isdigit(*s)) { + intval = 0; + numdigits = 0; + while (*s && isdigit(*s)) { + intval *= 10; + intval += *s - '0'; + numdigits++; + s++; + } + safe_format(buff, &bp, "%d", intval); + numdigits = 20 - numdigits; + while (numdigits > 0) { + safe_chr('0', buff, &bp); + numdigits--; + } + } + } + break; + case NUMBER_TOKEN: + if (isdigit(*(s + 1))) { + s++; + victim = 0; + while (*s && isdigit(*s)) { + victim *= 10; + victim += *s - '0'; + s++; + } + if (GoodObject(victim)) { + safe_str(Name(victim), buff, &bp); + } else { + safe_str("#-1 NO SUCH OBJECT VISIBLE", buff, &bp); + } + break; + } + default: + safe_chr(*s, buff, &bp); + } + if (*s) + s++; + } + *bp = '\0'; + rec->memo.str.s = mush_strdup(buff, "genrecord"); + rec->memo.str.freestr = 1; +} + GENRECORD(gen_dbref) { rec->memo.num = qparse_dbref(rec->val); @@ -275,8 +359,6 @@ GENRECORD(gen_float) rec->memo.numval = parse_number(rec->val); } -#define RealGoodObject(x) (GoodObject(x) && !IsGarbage(x)) - GENRECORD(gen_db_name) { rec->memo.str.s = (char *) ""; @@ -466,6 +548,7 @@ char INSENS_ALPHANUM_LIST[] = "I"; char DBREF_LIST[] = "D"; char NUMERIC_LIST[] = "N"; char FLOAT_LIST[] = "F"; +char MAGIC_LIST[] = "M"; char DBREF_NAME_LIST[] = "NAME"; char DBREF_NAMEI_LIST[] = "NAMEI"; char DBREF_IDLE_LIST[] = "IDLE"; @@ -484,6 +567,7 @@ list_type_list ltypelist[] = { {DBREF_LIST, gen_dbref, i_comp, 0}, {NUMERIC_LIST, gen_num, i_comp, 0}, {FLOAT_LIST, gen_float, f_comp, 0}, + {MAGIC_LIST, gen_magic, si_comp, 0}, {DBREF_NAME_LIST, gen_db_name, si_comp, IS_DB | IS_STRING}, {DBREF_NAMEI_LIST, gen_db_name, si_comp, IS_DB | IS_STRING}, {DBREF_IDLE_LIST, gen_db_idle, i_comp, IS_DB}, diff --git a/src/speech.c b/src/speech.c index a166b64..77145d5 100644 --- a/src/speech.c +++ b/src/speech.c @@ -358,7 +358,7 @@ do_whisper(dbref player, const char *arg1, const char *arg2, int noisy) tp = tbuf; safe_str(T(" to "), tbuf, &tp); for (who = 0; who < gcount; who++) { - if (noisy && (get_random_long(0, 100) < WHISPER_LOUDNESS)) + if (noisy && (get_random32(0, 100) < (uint32_t) WHISPER_LOUDNESS)) overheard = 1; safe_itemizer(who + 1, (who == gcount - 1), ",", T("and"), " ", tbuf, &tp); safe_str(Name(good[who]), tbuf, &tp); @@ -710,8 +710,8 @@ messageformat(dbref player, const char *attribute, dbref enactor, int flags, static char messbuff[BUFFER_LEN]; *messbuff = '\0'; - if (!call_attrib(player, attribute, (const char **) argv, numargs, - messbuff, enactor, NULL)) { + if (call_attrib(player, attribute, (const char **) argv, numargs, + messbuff, enactor, NULL)) { /* We have a returned value. Notify the player. */ if (*messbuff) notify_anything(enactor, na_one, &player, ns_esnotify, flags, messbuff); diff --git a/src/tables.c b/src/tables.c index e483bf9..e432d27 100644 --- a/src/tables.c +++ b/src/tables.c @@ -40,49 +40,6 @@ signed char qreg_indexes[256] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; -char from_base_64[256] = { - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, 62, -1, 63, - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, - -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, 63, - -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, - 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 -}; - -char to_base_64[] = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; - -char from_base_36[256] = { - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, - -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, - 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, - -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, - 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 -}; - -char to_base_36[] = "0123456789abcdefghijklmnopqrstuvwxyz"; - char active_table[256] = { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, @@ -197,6 +154,25 @@ char valid_ansi_codes[256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; +char soundex_val[256] = { + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 49, 50, 51, 48, 49, 50, 48, 48, 50, 50, 52, 53, 53, 48, + 49, 50, 54, 50, 51, 48, 49, 48, 50, 48, 50, 48, 48, 48, 48, 48, + 48, 48, 49, 50, 51, 48, 49, 50, 48, 48, 50, 50, 52, 53, 53, 48, + 49, 50, 54, 50, 51, 48, 49, 48, 50, 48, 50, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48 +}; + typedef struct { const char *base; const char *entity; @@ -362,7 +338,7 @@ accent_info accent_table[256] = { {NULL, NULL}, {NULL, NULL}, {NULL, NULL}, -{" ", " "}, +{NULL, NULL}, {"!", "¡"}, {NULL, NULL}, {NULL, NULL}, diff --git a/src/utils.c b/src/utils.c index caefcdb..c6b169f 100644 --- a/src/utils.c +++ b/src/utils.c @@ -48,6 +48,7 @@ #include "attrib.h" #include "parse.h" #include "lock.h" +#include "SFMT.h" #include "modules.h" @@ -55,9 +56,6 @@ extern struct module_entry_t *module_list; dbref find_entrance(dbref door); void initialize_mt(void); -uint32_t genrand_int32(void); -static void init_genrand(unsigned long); -static void init_by_array(unsigned long *, int); extern int local_can_interact_first(dbref from, dbref to, int type); extern int local_can_interact_last(dbref from, dbref to, int type); @@ -305,8 +303,8 @@ call_ufun(ufun_attrib * ufun, char **wenv_args, int wenv_argc, char *ret, * of the process_expression are stored in. * \param enactor The enactor. * \param pe_info The pe_info passed to the FUNCTION - * \retval 0 success - * \retval 1 No such attribute, or failed. + * \retval 1 success + * \retval 0 No such attribute, or failed. */ bool call_attrib(dbref thing, const char *attrname, const char *wenv_args[], @@ -327,22 +325,22 @@ call_attrib(dbref thing, const char *attrname, const char *wenv_args[], /* Make sure we have a valid object to call first */ if (!GoodObject(thing) || IsGarbage(thing)) - return 1; + return 0; if (attrname == NULL || !*attrname) - return 1; + return 0; /* Fetch the attrib contents */ attrib = (ATTR *) atr_get(thing, attrname); if (attrib == NULL) - return 1; + return 0; mush_strncpy(atrbuf, atr_value(attrib), BUFFER_LEN); if (!*atrbuf) { if (ret) *ret = '\0'; - return 0; + return 1; } save_global_regs("localize", saver); @@ -402,7 +400,7 @@ call_attrib(dbref thing, const char *attrname, const char *wenv_args[], restore_regexp_context(&rsave); restore_global_regs("localize", saver); - return pe_ret; + return !pe_ret; } /** Given an exit, find the room that is its source through brute force. @@ -542,29 +540,18 @@ reverse(dbref list) } -#define N 624 /**< PRNG constant */ - -/* We use the Mersenne Twister PRNG. It's quite good as PRNGS go, - * much better than the typical ones provided in system libc's. - * - * The following two functions are based on the reference implementation, - * with changes in the seeding function to use /dev/urandom as a seed - * if possible. - * - * The Mersenne Twister homepage is: - * http://www.math.keio.ac.jp/~matumoto/emt.html - * - * You can get the reference code there. - */ - -/** Wrapper to choose a seed and initialize the Mersenne Twister PRNG. */ +/** Wrapper to choose a seed and initialize the Mersenne Twister PRNG. + * The actual MT code lives in SFMT.c and hdrs/SFMT*.h */ void initialize_mt(void) { #ifdef HAS_DEV_URANDOM int fd; - unsigned long buf[N]; + uint32_t buf[4]; /* The linux manpage for /dev/urandom + advises against reading large amounts of + data from it; we used to read 624*4 (Or *8 on 64-bit systems) + bytes. The new figure is much more reasonable. */ fd = open("/dev/urandom", O_RDONLY); if (fd >= 0) { @@ -585,134 +572,13 @@ initialize_mt(void) #endif /* Default seeder. Pick a seed that's fairly random */ #ifdef WIN32 - init_genrand(GetCurrentProcessId() | (time(NULL) << 16)); + init_gen_rand(GetCurrentProcessId() | (time(NULL) << 16)); #else - init_genrand(getpid() | (time(NULL) << 16)); + init_gen_rand(getpid() | (time(NULL) << 16)); #endif } -/* A C-program for MT19937, with initialization improved 2002/1/26.*/ -/* Coded by Takuji Nishimura and Makoto Matsumoto. */ - -/* Before using, initialize the state by using init_genrand(seed) */ -/* or init_by_array(init_key, key_length). */ - -/* This library is free software. */ -/* This library is distributed in the hope that it will be useful, */ -/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ -/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. */ - -/* Copyright (C) 1997, 2002 Makoto Matsumoto and Takuji Nishimura. */ -/* Any feedback is very welcome. */ -/* http://www.math.keio.ac.jp/matumoto/emt.html */ -/* email: matumoto@math.keio.ac.jp */ - -/* Period parameters */ -#define M 397 /**< PRNG constant */ -#define MATRIX_A 0x9908b0dfUL /**< PRNG constant vector a */ -#define UPPER_MASK 0x80000000UL /**< PRNG most significant w-r bits */ -#define LOWER_MASK 0x7fffffffUL /**< PRNG least significant r bits */ - -static unsigned long mt[N]; /* the array for the state vector */ -static int mti = N + 1; /* mti==N+1 means mt[N] is not initialized */ - -/** initializes mt[N] with a seed. - * \param a seed value. - */ -static void -init_genrand(unsigned long s) -{ - mt[0] = s & 0xffffffffUL; - for (mti = 1; mti < N; mti++) { - mt[mti] = (1812433253UL * (mt[mti - 1] ^ (mt[mti - 1] >> 30)) + mti); - /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */ - /* In the previous versions, MSBs of the seed affect */ - /* only MSBs of the array mt[]. */ - /* 2002/01/09 modified by Makoto Matsumoto */ - mt[mti] &= 0xffffffffUL; - /* for >32 bit machines */ - } -} - -/** initialize by an array with array-length - * \param init_key the array for initializing keys - * \param key_length the array's length - */ -static void -init_by_array(unsigned long init_key[], int key_length) -{ - int i, j, k; - init_genrand(19650218UL); - i = 1; - j = 0; - k = (N > key_length ? N : key_length); - for (; k; k--) { - mt[i] = (mt[i] ^ ((mt[i - 1] ^ (mt[i - 1] >> 30)) * 1664525UL)) - + init_key[j] + j; /* non linear */ - mt[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */ - i++; - j++; - if (i >= N) { - mt[0] = mt[N - 1]; - i = 1; - } - if (j >= key_length) - j = 0; - } - for (k = N - 1; k; k--) { - mt[i] = (mt[i] ^ ((mt[i - 1] ^ (mt[i - 1] >> 30)) * 1566083941UL)) - - i; /* non linear */ - mt[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */ - i++; - if (i >= N) { - mt[0] = mt[N - 1]; - i = 1; - } - } - - mt[0] = 0x80000000UL; /* MSB is 1; assuring non-zero initial array */ -} - -/* generates a random number on [0,0xffffffff]-interval */ -uint32_t -genrand_int32(void) -{ - unsigned long y; - static unsigned long mag01[2] = { 0x0UL, MATRIX_A }; - /* mag01[x] = x * MATRIX_A for x=0,1 */ - - if (mti >= N) { /* generate N words at one time */ - int kk; - - if (mti == N + 1) /* if init_genrand() has not been called, */ - init_genrand(5489UL); /* a default initial seed is used */ - - for (kk = 0; kk < N - M; kk++) { - y = (mt[kk] & UPPER_MASK) | (mt[kk + 1] & LOWER_MASK); - mt[kk] = mt[kk + M] ^ (y >> 1) ^ mag01[y & 0x1UL]; - } - for (; kk < N - 1; kk++) { - y = (mt[kk] & UPPER_MASK) | (mt[kk + 1] & LOWER_MASK); - mt[kk] = mt[kk + (M - N)] ^ (y >> 1) ^ mag01[y & 0x1UL]; - } - y = (mt[N - 1] & UPPER_MASK) | (mt[0] & LOWER_MASK); - mt[N - 1] = mt[M - 1] ^ (y >> 1) ^ mag01[y & 0x1UL]; - - mti = 0; - } - - y = mt[mti++]; - - /* Tempering */ - y ^= (y >> 11); - y ^= (y << 7) & 0x9d2c5680UL; - y ^= (y << 15) & 0xefc60000UL; - y ^= (y >> 18); - - return y; -} - /** Get a uniform random long between low and high values, inclusive. * Based on MUX's RandomINT32() @@ -720,10 +586,10 @@ genrand_int32(void) * \param high upper bound for random number. * \return random number between low and high, or 0 or -1 for error. */ -long -get_random_long(long low, long high) +uint32_t +get_random32(uint32_t low, uint32_t high) { - unsigned long x, n, n_limit; + uint32_t x, n, n_limit; /* Validate parameters */ if (high < low) { @@ -732,11 +598,7 @@ get_random_long(long low, long high) return low; } - x = high - low; - if (LONG_MAX < x) { - return -1; - } - x++; + x = high - low + 1; /* We can now look for an random number on the interval [0,x-1]. // @@ -755,10 +617,10 @@ get_random_long(long low, long high) // we will call getrand() is less than 2. */ - n_limit = ULONG_MAX - (ULONG_MAX % x); + n_limit = UINT32_MAX - (UINT32_MAX % x); do { - n = genrand_int32(); + n = gen_rand32(); } while (n >= n_limit); return low + (n % x); diff --git a/src/version.c b/src/version.c index 0a364ae..ec9de19 100644 --- a/src/version.c +++ b/src/version.c @@ -41,6 +41,5 @@ do_version(player) notify_format(player, T("Build date: %s"), BUILDDATE); notify_format(player, T("Compiler: %s"), COMPILER); notify_format(player, T("Compilation flags: %s"), CCFLAGS); - notify_format(player, T("Malloc package: %d"), MALLOC_PACKAGE); #endif } diff --git a/src/wild.c b/src/wild.c index 4170f69..0dea11d 100644 --- a/src/wild.c +++ b/src/wild.c @@ -44,6 +44,17 @@ /** Maximum number of wildcarded arguments */ #define NUMARGS (10) +/** Skip across all ansi and pueblo markup. */ +#define SKIP_ANSI(x) do { \ + if (*x == TAG_START) { \ + while (*x && (*x != TAG_END)) x++; \ + if (*x) x++; \ + } else if (*x == ESC_CHAR) { \ + while (*x && (*x != 'm')) x++; \ + if (*x) x++; \ + } \ + } while ((*x == TAG_START) || (*x == ESC_CHAR)) + const unsigned char *tables = NULL; /** Pointer to character tables */ static bool wild1 @@ -89,6 +100,7 @@ bool quick_wild_new(const char *restrict tstr, const char *restrict dstr, bool cs) { while (*tstr != '*') { + SKIP_ANSI(dstr); switch (*tstr) { case '?': /* Single character match. Return false if at @@ -129,6 +141,7 @@ quick_wild_new(const char *restrict tstr, const char *restrict dstr, bool cs) if (!*dstr) return 0; dstr++; + SKIP_ANSI(dstr); } tstr++; } @@ -146,6 +159,7 @@ quick_wild_new(const char *restrict tstr, const char *restrict dstr, bool cs) if (EQUAL(cs, *dstr, *tstr) && quick_wild_new(tstr + 1, dstr + 1, cs)) return 1; dstr++; + SKIP_ANSI(dstr); } return 0; } @@ -172,6 +186,7 @@ atr_wild(const char *restrict tstr, const char *restrict dstr) return !strchr(dstr, '`'); while (*tstr != '*') { + SKIP_ANSI(dstr); switch (*tstr) { case '?': /* Single character match. Return false if at @@ -216,6 +231,7 @@ atr_wild(const char *restrict tstr, const char *restrict dstr) if (!*dstr || *dstr == '`') return 0; dstr++; + SKIP_ANSI(dstr); starcount = 0; } else starcount++; @@ -236,6 +252,7 @@ atr_wild(const char *restrict tstr, const char *restrict dstr) if (*dstr != '`' && atr_wild(tstr + 1, dstr + 1)) return 1; dstr++; + SKIP_ANSI(dstr); } } else { /* Skip over a backslash in the pattern string if it is there. */ @@ -253,6 +270,7 @@ atr_wild(const char *restrict tstr, const char *restrict dstr) if (starcount < 2 && *dstr == '`') return 0; dstr++; + SKIP_ANSI(dstr); } } return 0; @@ -275,6 +293,7 @@ wild1(const char *restrict tstr, const char *restrict dstr, int arg, int argpos, numextra; while (*tstr != '*') { + SKIP_ANSI(dstr); switch (*tstr) { case '?': /* Single character match. Return false if at @@ -354,6 +373,7 @@ wild1(const char *restrict tstr, const char *restrict dstr, int arg, *(*wbuf)++ = '\0'; *len -= 2; } + SKIP_ANSI(datapos); /* Jump to the fast routine if we can. */ if (argpos >= (int) max || *len < 1) @@ -371,6 +391,7 @@ wild1(const char *restrict tstr, const char *restrict dstr, int arg, return 0; tstr++; dstr++; + SKIP_ANSI(dstr); arg++; numextra++; } @@ -383,10 +404,12 @@ wild1(const char *restrict tstr, const char *restrict dstr, int arg, /* Check for possible matches. This loop terminates either at * end of data (resulting in failure), or at a successful match. */ - if (!*tstr) - while (*dstr) + if (!*tstr) { + while (*dstr) { dstr++; - else { + SKIP_ANSI(dstr); + } + } else { while (1) { if (EQUAL(cs, *dstr, *tstr) && ((arg < (int) max) ? wild1(tstr, dstr, arg, wbuf, len, cs, ary, max) @@ -395,6 +418,7 @@ wild1(const char *restrict tstr, const char *restrict dstr, int arg, if (!*dstr) return 0; dstr++; + SKIP_ANSI(dstr); } } @@ -411,6 +435,7 @@ wild1(const char *restrict tstr, const char *restrict dstr, int arg, *(*wbuf)++ = '\0'; *len -= datalen + 1; datapos = dstr - numextra; + SKIP_ANSI(datapos); } } @@ -425,6 +450,7 @@ wild1(const char *restrict tstr, const char *restrict dstr, int arg, *len -= 2; numextra--; } + SKIP_ANSI(datapos); } /* It's done! */ @@ -447,6 +473,7 @@ wild(const char *restrict s, const char *restrict d, int p, bool cs, /* Do fast match to see if pattern matches. If yes, do it again, remembering this time.. */ while ((*s != '*') && (*s != '?')) { + SKIP_ANSI(d); if (*s == '\\') s++; if (NOTEQUAL(cs, *d, *s)) @@ -708,7 +735,10 @@ check_literals(const char *restrict tstr, const char *restrict dstr, bool cs) char dbuf1[BUFFER_LEN]; const char delims[] = "?*"; char *sp, *dp; - mush_strncpy(dbuf1, dstr, BUFFER_LEN); + size_t len = 0; + + dp = remove_markup(dstr, &len); + memcpy(dbuf1, dp, len); mush_strncpy(tbuf1, strip_backslashes(tstr), BUFFER_LEN); if (!cs) { upcasestr(tbuf1); @@ -717,7 +747,7 @@ check_literals(const char *restrict tstr, const char *restrict dstr, bool cs) dp = dbuf1; sp = strtok(tbuf1, delims); while (sp) { - if (!dp) + if (!dp || !*dp) return 0; if (!(dp = strstr(dp, sp))) return 0; diff --git a/src/wiz.c b/src/wiz.c index 73473d2..6470e5c 100644 --- a/src/wiz.c +++ b/src/wiz.c @@ -80,6 +80,8 @@ struct search_spec { int count; /**< Limited results: return this many */ int end; /**< Limited results: return until this one.*/ boolexp lock; /**< Boolexp to check against the objects. */ + char cmdstring[BUFFER_LEN]; + char listenstring[BUFFER_LEN]; }; int tport_dest_ok(dbref player, dbref victim, dbref dest); @@ -104,10 +106,12 @@ extern char errlog[BUFFER_LEN]; * \param creator the enactor. * \param player_name name of player to create. * \param player_password password for player. + * \param try_dbref if non-empty, the garbage object to use for the new player. * \return dbref of created player object, or NOTHING if failure. */ dbref -do_pcreate(dbref creator, const char *player_name, const char *player_password) +do_pcreate(dbref creator, const char *player_name, const char *player_password, + const char *try_dbref) { dbref player; @@ -117,7 +121,13 @@ do_pcreate(dbref creator, const char *player_name, const char *player_password) } if (!can_pay_fees(creator, 0)) return NOTHING; - player = create_player(player_name, player_password, "None", "None"); + + if (try_dbref && *try_dbref) + player = parse_dbref(try_dbref); + else + player = NOTHING; + + player = create_player(player_name, player_password, "None", "None", player); if (player == NOTHING) { notify_format(creator, T("Failure creating '%s' (bad name)"), player_name); return NOTHING; @@ -1752,6 +1762,8 @@ fill_search_spec(dbref player, const char *owner, int nargs, const char **args, spec->start = 1; /* 1-indexed */ spec->count = 0; spec->lock = TRUE_BOOLEXP; + strcpy(spec->cmdstring, ""); + strcpy(spec->listenstring, ""); /* set limits on who we search */ if (!owner || !*owner || strcasecmp(owner, "all") == 0) @@ -1938,6 +1950,10 @@ fill_search_spec(dbref player, const char *owner, int nargs, const char **args, spec->lock = parse_boolexp(player, restriction, "Search"); } else if (string_prefix("eval", class)) { strcpy(spec->eval, restriction); + } else if (string_prefix("command", class)) { + strcpy(spec->cmdstring, restriction); + } else if (string_prefix("listen", class)) { + strcpy(spec->listenstring, restriction); } else if (string_prefix("ethings", class) || string_prefix("eobjects", class)) { strcpy(spec->eval, restriction); @@ -1996,6 +2012,9 @@ raw_search(dbref player, const char *owner, int nargs, const char **args, int n; struct search_spec spec; int count = 0; + int ret = 0; + ATTR *a; + char lbuff[BUFFER_LEN]; /* make sure player has money to do the search */ if (!payfor(player, FIND_COST)) { @@ -2064,6 +2083,27 @@ raw_search(dbref player, const char *owner, int nargs, const char **args, } if(spec.lock != TRUE_BOOLEXP && !eval_boolexp(n, spec.lock, player, NULL)) continue; + if (spec.cmdstring[0] && + !atr_comm_match(n, player, '$', ':', spec.cmdstring, 1, 0, + NULL, NULL, NULL)) + continue; + if (spec.listenstring[0]) { + ret = 0; + /* do @listen stuff */ + a = atr_get_noparent(n, "LISTEN"); + if (a) { + strcpy(lbuff, atr_value(a)); + ret = AF_Regexp(a) + ? regexp_match_case_r(lbuff, spec.listenstring, + AF_Case(a), NULL, 0, NULL, 0) + : wild_match_case_r(lbuff, spec.listenstring, + AF_Case(a), NULL, 0, NULL, 0); + } + if (!ret && + !atr_comm_match(n, player, '^', ':', spec.listenstring, 1, 0, + NULL, NULL, NULL)) + continue; + } if (*spec.eval) { char *ebuf1; const char *ebuf2; diff --git a/test/PennMUSH.pm b/test/PennMUSH.pm index 8bf8e29..df46cac 100644 --- a/test/PennMUSH.pm +++ b/test/PennMUSH.pm @@ -68,7 +68,7 @@ sub start { } elsif (defined($child)) { chdir("testgame"); my @execargs = ("./netmush", "--no-session", "test.cnf"); - unshift @execargs, "valgrind", '--log-file=../valgrind-%p.log' + unshift @execargs, "valgrind", "--tool=memcheck", '--log-file=../valgrind-%p.log', "--leak-check=full" if $self->{VALGRIND}; exec @execargs; } else { diff --git a/test/testhastype.pl b/test/testhastype.pl index 1b14e46..90b2587 100644 --- a/test/testhastype.pl +++ b/test/testhastype.pl @@ -2,11 +2,11 @@ expect 2 failures! run tests: test('hastype.1', $god, 'think hastype(#0, room)', ['1', '!#-1']); test('hastype.2', $god, 'think hastype(#1, player)', ['1', '!#-1']); -test('hastype.3', $god, '@create foo', []); -test('hastype.4', $god, 'think hastype(foo, thing)', ['1', '!#-1']); -test('hastype.5', $god, '@rec foo', []); -test('hastype.6', $god, '@rec foo', []); -test('hastype.7', $god, 'think hastype(#3, garbage)', ['1', '!#-1']); -test('hastype.8', $god, '@open foo', []); -test('hastype.9', $god, 'think hastype(#3, exit)', ['1', '!#-1']); +$god->command('@create foo'); +test('hastype.3', $god, 'think hastype(foo, thing)', ['1', '!#-1']); +$god->command('@rec foo'); +$god->command('@rec foo'); +test('hastype.4', $god, 'think hastype(#3, garbage)', ['1', '!#-1']); +$god->command('@open foo'); +test('hastype.5', $god, 'think hastype(#3, exit)', ['1', '!#-1']); diff --git a/utils/gentables.c b/utils/gentables.c index b6e9d39..bacc396 100644 --- a/utils/gentables.c +++ b/utils/gentables.c @@ -117,6 +117,17 @@ char ansi_codes[UCHAR_MAX + 1] = { ['/'] = 1, ['a'] = 1 }; +/* Values used in soundex hashing */ +char soundex_codes[UCHAR_MAX + 1] = { + ['B'] = 1, ['P'] = 1, ['F'] = 1, ['V'] = 1, ['b'] = 1, ['p'] = 1, ['f'] = 1, ['v'] = 1, + ['C'] = 2, ['G'] = 2, ['J'] = 2, ['K'] = 2, ['Q'] = 2, ['S'] = 2, ['X'] = 2, ['Z'] = 2, + ['c'] = 2, ['g'] = 2, ['j'] = 2, ['k'] = 2, ['q'] = 2, ['s'] = 2, ['x'] = 2, ['z'] = 2, + ['D'] = 3, ['T'] = 3, ['d'] = 3, ['t'] = 3, + ['L'] = 4, ['l'] = 4, + ['M'] = 5, ['N'] = 5, ['m'] = 5, ['n'] = 5, + ['R'] = 6, ['r'] = 6 +}; + /** Accented characters * * The table is for ISO 8859-1 character set. @@ -265,6 +276,7 @@ void print_entity_table(const char *name, } + int main(int argc, char *argv[]) { printf("/* This file was generated by running %s compiled from\n" " * %s. Edit that file, not this one, when making changes. */\n" @@ -276,6 +288,7 @@ int main(int argc, char *argv[]) { print_table_bool("char", "valid_timefmt_codes", valid_timefmt_codes, 0); print_table_bool("char", "escaped_chars", escaped_chars, 0); print_table_bool("char", "valid_ansi_codes", ansi_codes, 0); + print_table_bool("char", "soundex_val", soundex_codes, '0'); print_entity_table("accent_table", entity_table); return EXIT_SUCCESS; }