* 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.
+-----------------------------------------------------------------------------
+
#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
#undef HAVE__VSNPRINTF_S
+#undef HAVE_VASPRINTF
+
+#undef HAVE_STRCHRNUL
#undef HAVE_STRDUP
#undef HAVE_EPOLL_CTL
-#undef HAVE_VALLOC
+#undef HAVE_POSIX_MEMALIGN
#undef HAVE_WRITEV
#undef HAVE_PWRITE
+#undef HAVE_POSIX_FADVISE
+
+#undef HAVE_POSIX_FALLOCATE
+
/* Variables and defines */
#undef HAVE_H_ERRNO
#undef DONT_TRANSLATE
+#undef INFO_SLAVE
+
#undef HAVE_UPTIME
/* Path to uptime */
/* Path to sendmail */
#undef SENDMAIL
+#undef HAVE_ED
+#undef ED_PATH
+
#undef HAVE_SAFE_TOUPPER
/* Optional language features */
#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
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], [], [], [
;;
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
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.
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
AC_CHECK_LIB(crypt, crypt)
LIB_SOCKET_NSL
AC_CHECK_LIB(fam, FAMOpen)
+AC_CHECK_LIB(z, gzungetc)
# with_ssl=set
CHECK_SSL
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
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)])
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
+
+
#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
# 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.
/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 <channel> = <object>
+
+ The Mogrifier lets you tweak every aspect of a channel's output, before
+ it goes to individual players' @chatformats.
+
+ <object> 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: "<Public>").
+ MOGRIFY`TITLE: %0 = The player's title, if any.
+ MOGRIFY`PLAYERNAME: %0 = The player's name.
+ MOGRIFY`SPEECHTEXT: %0 = "says"
+ MOGRIFY`MESSAGE: %0 = <the content of the say, pose, semipose or emit>
+
+ 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
+<Public> 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:
@config/attribs
@config/flags
@config/list[/lowercase] [<option|option-type>]
- @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.
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 <object> [=<format>]
See also: ATTRIBUTES, NON-STANDARD ATTRIBUTES
& @create
- @create <name> [=<cost>]
+ @create <name>[=<cost>[,<dbref>]]
Creates a thing with the specified name. Creating a thing costs
a certain amount of MUSH money, which usually defaults to 10 pennies.
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
See also: give
& @pcreate
- @pcreate <name> = <password>
+ @pcreate <name> = <password>[, <dbref>]
This Director-only command creates a player with the given name and
password.
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.
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 */
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,
#define BOOLEXP_H
#include "copyrite.h"
#include "chunk.h"
+#include "dbio.h"
typedef chunk_reference_t boolexp;
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 */
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? */
#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)
#include <setjmp.h>
#include <stdio.h>
+#ifdef HAVE_ZLIB_H
+#include <zlib.h>
+#endif
#ifdef HAVE_STDINT_H
#include <stdint.h>
#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
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);
/* 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);
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);
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,
#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);
/* 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);
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);
#include "mushtype.h"
#include "ptab.h"
+#include "dbio.h"
#include "division.h"
typedef struct flag_info FLAG;
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);
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.
*/
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,
/* From compress.c */
#if (COMPRESSION_TYPE > 0)
-extern int init_compress(FILE * f);
+int init_compress(PENNFILE *f);
#endif
/* From conf.c */
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);
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);
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 */
#ifndef _SHS_H
#define _SHS_H
-#include "config.h"
-#ifdef HAVE_STDINT
+#ifdef HAVE_STDINT_H
#include <stdint.h>
#endif
#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
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
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.)
-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:
ME
MEMBERS
MOD
+MOGRIFIER
MORTAL
MOTD
MUTE
ROOM
ROOMS
RSARGS
+SAVE
SEE
SEEFLAG
SELF
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)
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
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) {
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;
* 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;
/** 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) {
return atr;
atr = AL_NEXT(atr);
}
+#endif
return NULL;
}
*/
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;
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;
#include "dbdefs.h"
#include "flags.h"
#include "lock.h"
-#include "help.h"
#include "match.h"
#include "ansi.h"
#include "pueblo.h"
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;
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,
DESC *d, *dnext;
const char *shutmsg;
int shutlen;
+ ssize_t res;
shutmsg = T(shutdown_message);
shutlen = strlen(shutmsg);
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);
{
dbref loc;
char tbuf1[BUFFER_LEN];
+ char *message;
char *myenv[2];
dbref zone;
dbref obj;
/* 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))
#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);
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)
{
int num;
DESC *d;
char tbuf1[BUFFER_LEN];
+ /* TODO: See above, char *message; */
dbref zone, obj;
int j;
struct module_entry_t *m;
void
dump_reboot_db(void)
{
- FILE *f;
+ PENNFILE *f;
DESC *d;
SU_PATH *exit_path;
long flags = RDBF_SCREENSIZE | RDBF_TTYPE | RDBF_PUEBLO_CHECKSUM
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
putstring(f, poll_msg);
putref(f, globals.first_start_time);
putref(f, globals.reboot_count);
- fclose(f);
+ penn_fclose(f);
}
}
void
load_reboot_db(void)
{
- FILE *f;
+ PENNFILE *f;
DESC *d = NULL;
DESC *closed = NULL, *nextclosed;
int val;
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;
* 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);
}
#endif
- fclose(f);
+ penn_fclose(f);
remove(REBOOTFILE);
flag_broadcast(0, 0, T("GAME: Reboot finished."));
}
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
#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.
#include <limits.h>
#include <string.h>
#include <stdlib.h>
+
+#define _XOPEN_SOURCE 600
#include <stdarg.h>
#include <fcntl.h>
#include <assert.h>
#include <wtypes.h>
#include <io.h>
#else
-#define _XOPEN_SOURCE 500
#define __USE_UNIX98
#include <unistd.h>
#endif
#include <errno.h>
+#ifdef I_SYS_STAT
+#include <sys/stat.h>
+#endif
+
#include "externs.h"
#include "boolexp.h"
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
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;
rhp->prev = prev;
rhp->next = next;
+#ifdef HAVE_POSIX_FADVISE
+ posix_fadvise(swap_fd, 0, 0, POSIX_FADV_RANDOM);
+#endif
+
return 1;
}
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;
}
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);
}
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)
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)
#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,
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);
}
}
#include "externs.h"
#include "mushdb.h"
#include "mymalloc.h"
+#include "dbio.h"
#ifdef WIN32
#pragma warning( disable : 4244) /* NJG: disable warning re conversion */
#endif
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.
* \param f filehandle to read from to build the tree.
*/
int
-init_compress(FILE * f)
+init_compress(PENNFILE *f)
{
int total;
unsigned char c;
/* 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++;
}
}
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);
* \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);
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);
* \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);
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
+#include <errno.h>
#include "conf.h"
#include "externs.h"
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 */
{"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"}
{"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"}
,
#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
* 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.
}
return 0;
}
+ if (source == 2)
+ append_restriction("restrict_command", val, p);
return 1;
} else if (!strcasecmp(opt, "restrict_function")) {
if (!restrictions)
}
return 0;
}
+ if (source == 2)
+ append_restriction("restrict_function", val, p);
return 1;
} else if (!strcasecmp(opt, "reserve_alias")) {
if (!restrictions)
}
return 0;
}
+ if (source == 2)
+ append_restriction("reserve_alias", val, p);
return 1;
} else if (!strcasecmp(opt, "attribute_alias")) {
if (!restrictions)
}
return 0;
}
+ if (source == 2)
+ append_restriction("attribute_alias", val, p);
return 1;
} else if (!strcasecmp(opt, "function_alias")) {
if (!restrictions)
}
return 0;
}
+ if (source == 2)
+ append_restriction("function_alias", val, p);
return 1;
} else if (!strcasecmp(opt, "help_command")
|| !strcasecmp(opt, "ahelp_command")) {
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,
&& 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;
}
}
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;
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;
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);
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);
/* 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;
}
}
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;
}
}
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));
}
}
}
/** 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;
/* 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;
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;
}
}
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
}
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)
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();
}
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
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."));
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;
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);
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;
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);
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;
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++) {
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);
/* 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;
* \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);
} 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();
memcpy(REFDB(clone), REFDB(thing), sizeof(struct object));
Owner(clone) = Owner(player);
- Name(clone) = NULL;
if (newname && *newname)
set_name(clone, newname);
else
#include "cron.h"
#include <ctype.h>
-#ifdef I_STRING
#include <string.h>
-#endif
#ifdef MUSHCRON
#include "copyrite.h"
#include "config.h"
-
+#define _GNU_SOURCE
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <time.h>
#endif
#include <stdlib.h>
+#include <stdarg.h>
+#include <errno.h>
#include <ltdl.h>
#include "conf.h"
#include "dbio.h"
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;
* \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.
* \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.
* 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;
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')
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)
/* 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') {
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);
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);
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 */
* 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;
* \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;
* \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);
* \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;
* \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);
* \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;
* \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);
* \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;
* \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);
}
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.
* \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));
}
* \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;
* \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);
* \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;
* \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;
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__
#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);
}
* \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;
* \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;
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++) {
#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;
* \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);
}
* \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);
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';
* \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);
* \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;
for (;;) {
int ch;
- ch = fgetc(f);
- ungetc(ch, f);
+ ch = penn_fgetc(f);
+ penn_ungetc(ch, f);
if (ch != ' ')
break;
* \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';
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;
* \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;
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);
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;
}
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];
for(;;) {
int c;
- c = fgetc(f);
- ungetc(c, f);
+ c = penn_fgetc(f);
+ penn_ungetc(c, f);
if (c != ' ')
break;
/* 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;
}
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");
}
} 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;
return 0;
}
-void db_write_flag_db(FILE *f) {
+void db_write_flag_db(PENNFILE *f) {
int flags;
/* Write out db flags */
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);
}
*/
static dbref
-db_read_oldstyle(FILE * f)
+db_read_oldstyle(PENNFILE *f)
{
int c, opbits;
dbref i;
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 '~':
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");
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;
* \return number of objects in the database.
*/
dbref
-db_read(FILE * f)
+db_read(PENNFILE *f)
{
int c;
dbref i = 0;
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;
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");
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;
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;
#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;
+}
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.
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 *);
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);
/* Database Functions {{{2 */
/* powers_read_all() {{{3 */
void
-powers_read_all(FILE * in)
+powers_read_all(PENNFILE * in)
{
int count;
/* 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;
/* powergroup_read() {{{3 - database powergroup read routine */
static void
-powergroup_read(FILE * in)
+powergroup_read(PENNFILE * in)
{
POWERGROUP *pgrp;
div_pbits dbits;
/* power_read_alias() {{{3 */
static void
-power_read_alias(FILE * in)
+power_read_alias(PENNFILE * in)
{
POWER *power;
char alias_name[BUFFER_LEN];
/* power_write_all() {{{3 */
void
-power_write_all(FILE * file)
+power_write_all(PENNFILE * file)
{
POWER *power;
POWERGROUP *pgrp;
}
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;
+
/**
* \file extmail.c
*
* \return number of mail messages saved.
*/
int
-dump_mail(FILE * fp)
+dump_mail(PENNFILE *fp)
{
MAIL *mp;
int count = 0;
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);
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;
}
* \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;
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);
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)
}
{
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)
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);
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 */
/* 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;
}
static FLAG *
-flag_alias_read_oldstyle(FILE * in, char *alias)
+flag_alias_read_oldstyle(PENNFILE * in, char *alias)
{
FLAG *f;
char *c;
* \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;
/* Read in a flag from a file and return it */
static FLAG *
-flag_read(FILE * in)
+flag_read(PENNFILE *in)
{
FLAG *f;
char *c;
}
static FLAG *
-flag_alias_read(FILE * in, char *alias, FLAGSPACE *n)
+flag_alias_read(PENNFILE *in, char *alias, FLAGSPACE *n)
{
FLAG *f;
char *c;
* \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;
for (;;) {
int c;
- c = fgetc(in);
- ungetc(c, in);
+ c = penn_fgetc(in);
+ penn_ungetc(c, in);
if (c != ' ')
break;
for (found = 0 ;;) {
int c;
- c = fgetc(in);
- ungetc(c, in);
+ c = penn_fgetc(in);
+ penn_ungetc(c, in);
if (c != ' ')
break;
flag_add_additional();
}
-static void flag_fake_read(FILE *f) {
+static void flag_fake_read(PENNFILE *f) {
int count;
/* Read shit into NULL-ville */
/* 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));
/* 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);
* \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;
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) {
twiddle_flag(thing, f, negate);
+ current = sees_flag(player, thing, f->name);
+
#ifdef RPMODE_SYS
if(is_flag(f, "RPMODE")) {
dbref oldloc;
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);
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);
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
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);
} else if (dlen == 0)
break;
else {
+ BIO_free_all(bio);
*bp = sbp;
safe_str(T("#-1 CONVERSION ERROR"), buff, bp);
return false;
#endif
}
+#ifdef HAVE_SSL
static void
safe_hexchar(unsigned char c, char *buff, char **bp)
{
(*bp)++;
}
}
+#endif /* HAVE_SSL */
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.
{"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},
{"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},
void
function_init_postconfig(void)
{
- userfn_tab = mush_calloc(MAX_GLOBAL_FNS, sizeof(USERFN_ENTRY), "userfn_tab");
}
/** Check permissions to run a function.
* User-defined global function handlers
*/
-
-static size_t userfn_count = 0;
-
static int
apply_restrictions(unsigned int result, const char *xres)
{
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
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);
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
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 {
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;
/* 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)
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;
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)
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.
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;
}
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);
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;
}
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) {
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 */
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 */
#include "copyrite.h"
#include "config.h"
-#ifdef I_STRING
#include <string.h>
-#else
#include <strings.h>
-#endif
#include "conf.h"
#include "externs.h"
#include "division.h"
#include "copyrite.h"
#include "config.h"
+#define _GNU_SOURCE
#include <string.h>
#include <ctype.h>
#include "conf.h"
/* 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;
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) {
#include <string.h>
#include <ctype.h>
#include <errno.h>
+
+#ifdef HAVE_SSE2
+#include <emmintrin.h>
+#endif
+#ifdef HAVE_SSE3
+#include <pmmintrin.h>
+#endif
#include "conf.h"
#include "externs.h"
#include "sort.h"
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);
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);
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);
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];
}
}
- // 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;
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--;
return;
}
- safe_integer(get_random_long(low, high), buff, bp);
+ safe_integer(get_random32(low, high), buff, bp);
}
/* ARGSUSED */
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);
}
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 *
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++;
}
FUNCTION(fun_strmatch)
{
char tbuf[BUFFER_LEN];
+ char pattern[BUFFER_LEN];
char *ret[36];
char *t;
size_t len;
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);
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;
} 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;
(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;
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;
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);
char realdumpfile[2048];
char realtmpfl[2048];
char tmpfl[2048];
- FILE *f = NULL;
+ PENNFILE *f = NULL;
struct module_entry_t *m;
void (*handle)();
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);
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
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);
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
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
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) {
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 {
#ifdef CHAT_SYSTEM
save_chatdb(f);
#endif /* CHAT_SYSTEM */
- fclose(f);
+ penn_fclose(f);
do_rawlog(LT_ERR, T("DUMPING: %s (done)"), panicfile);
}
}
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)
int
init_game_dbs(void)
{
- FILE *f;
+ PENNFILE *f;
int c;
const char *infile, *outfile;
#ifdef USE_MAILER
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;
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);
return 0;
}
- ungetc(c, f);
+ penn_ungetc(c, f);
if (setjmp(db_err) == 0) {
/* ok, read it in */
do_rawlog(LT_ERR, "ANALYZING: %s (done)", infile);
/* everything ok */
- db_close(f);
+ penn_fclose(f);
f = db_open(infile);
if (!f)
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);
* 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)))
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);
dbline = 0;
load_mail(f);
do_rawlog(LT_ERR, "LOADING: %s (done)", mailfile);
- db_close(f);
+ penn_fclose(f);
}
}
#endif /* USE_MAILER */
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;
}
}
do_rawlog(LT_ERR, "ERROR LOADING %s", options.chatdb);
return -1;
}
- db_close(f);
+ penn_fclose(f);
}
}
#endif /* CHAT_SYSTEM */
/** 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) { \
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);
/** 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
}
-/* 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
"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.
#include <ctype.h>
#include <stdio.h>
#include <errno.h>
+#include <fcntl.h>
#include "conf.h"
#include "externs.h"
#include "boolexp.h"
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) {
#ifdef HAVE_STDINT_H
#include <stdint.h>
#endif
+#ifdef HAS_OPENSSL
+#include <openssl/bn.h>
+#endif
#include "conf.h"
#include "externs.h"
return hash;
}
-typedef uint32_t(*hash_func) (const char *, int);
+typedef uint32_t (*hash_func) (const char *, int);
hash_func hash_functions[] = {
hsieh_hash,
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,
return val + 1;
else
return primes[n];
+#endif
}
/** Initialize a hashtable.
}
/* 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];
#ifdef I_SYS_TYPES
#include <sys/types.h>
#endif
-#include <time.h>
#ifdef I_SYS_TIME
#include <sys/time.h>
#ifdef TIME_WITH_SYS_TIME
#include "match.h"
#include "log.h"
#include "flags.h"
-#include "dbdefs.h"
#include "mymalloc.h"
#include "strtree.h"
#include "privtab.h"
#include <time.h>
#endif
#endif
-#include <time.h>
#ifdef I_SYS_TYPES
#include <sys/types.h>
#endif
#include "config.h"
#include "copyrite.h"
-
+#define _GNU_SOURCE
#include <string.h>
#include <ctype.h>
* \param fp file pointer to read from.
*/
void
-load_malias(FILE * fp)
+load_malias(PENNFILE *fp)
{
int i, j;
char buffer[BUFFER_LEN];
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"));
* \param fp file pointer to write to.
*/
void
-save_malias(FILE * fp)
+save_malias(PENNFILE *fp)
{
int i, j;
struct mail_alias *m;
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;
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
#include <stddef.h>
#include <limits.h>
#include <assert.h>
+#include <errno.h>
+#include <string.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#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.
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;
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
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. */
#include <stdio.h>
#include <stdarg.h>
-#ifdef I_SYS_TYPES
-#include <sys/types.h>
-#endif
#ifdef WIN32
#define FD_SETSIZE 256
#include <windows.h>
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.
*/
int n;
for (n = 0; n < 4; n++)
- gibberish[n] = genrand_int32();
+ gibberish[n] = gen_rand32();
RAND_seed(gibberish, sizeof gibberish);
&& 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
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];
+
+
pcre_get_substring_list(const char *subject, int *ovector, int stringcount,
const char ***listptr);
+
+
pcre_get_substring(const char *subject, int *ovector, int stringcount,
int stringnumber, const char **stringptr);
+
+
pcre_get_named_substring(const pcre * code, const char *subject, int *ovector,
int stringcount, const char *stringname,
const char **stringptr);
+
+
compile_regex(int, int, int *, uschar **, const uschar **, int *, BOOL, int,
int *, int *, branch_chain *, compile_data *);
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.
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);
* \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)) {
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;
}
/* 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
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);
static dbref
make_player(const char *name, const char *password, const char *host,
- const char *ip)
+ const char *ip, dbref try_dbref)
{
dbref player;
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 */
#include "config.h"
#include <string.h>
+#include <ctype.h>
#include <math.h>
#include "conf.h"
#include "externs.h"
/* 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;
dbref player __attribute__ ((__unused__)), \
char *sortflags __attribute__ ((__unused__)))
-
-
GENRECORD(gen_alphanum)
{
size_t len;
}
}
+#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);
rec->memo.numval = parse_number(rec->val);
}
-#define RealGoodObject(x) (GoodObject(x) && !IsGarbage(x))
-
GENRECORD(gen_db_name)
{
rec->memo.str.s = (char *) "";
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";
{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},
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);
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);
-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,
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;
{NULL, NULL},
{NULL, NULL},
{NULL, NULL},
-{" ", " "},
+{NULL, NULL},
{"!", "¡"},
{NULL, NULL},
{NULL, NULL},
#include "attrib.h"
#include "parse.h"
#include "lock.h"
+#include "SFMT.h"
#include "modules.h"
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);
* 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[],
/* 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);
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.
}
-#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) {
#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()
* \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) {
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].
//
// 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);
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
}
/** 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
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
if (!*dstr)
return 0;
dstr++;
+ SKIP_ANSI(dstr);
}
tstr++;
}
if (EQUAL(cs, *dstr, *tstr) && quick_wild_new(tstr + 1, dstr + 1, cs))
return 1;
dstr++;
+ SKIP_ANSI(dstr);
}
return 0;
}
return !strchr(dstr, '`');
while (*tstr != '*') {
+ SKIP_ANSI(dstr);
switch (*tstr) {
case '?':
/* Single character match. Return false if at
if (!*dstr || *dstr == '`')
return 0;
dstr++;
+ SKIP_ANSI(dstr);
starcount = 0;
} else
starcount++;
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. */
if (starcount < 2 && *dstr == '`')
return 0;
dstr++;
+ SKIP_ANSI(dstr);
}
}
return 0;
int argpos, numextra;
while (*tstr != '*') {
+ SKIP_ANSI(dstr);
switch (*tstr) {
case '?':
/* Single character match. Return false if at
*(*wbuf)++ = '\0';
*len -= 2;
}
+ SKIP_ANSI(datapos);
/* Jump to the fast routine if we can. */
if (argpos >= (int) max || *len < 1)
return 0;
tstr++;
dstr++;
+ SKIP_ANSI(dstr);
arg++;
numextra++;
}
/* 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)
if (!*dstr)
return 0;
dstr++;
+ SKIP_ANSI(dstr);
}
}
*(*wbuf)++ = '\0';
*len -= datalen + 1;
datapos = dstr - numextra;
+ SKIP_ANSI(datapos);
}
}
*len -= 2;
numextra--;
}
+ SKIP_ANSI(datapos);
}
/* It's done! */
/* 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))
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);
dp = dbuf1;
sp = strtok(tbuf1, delims);
while (sp) {
- if (!dp)
+ if (!dp || !*dp)
return 0;
if (!(dp = strstr(dp, sp)))
return 0;
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);
* \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;
}
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;
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)
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);
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)) {
}
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;
} 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 {
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']);
['/'] = 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.
}
+
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"
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;
}