This is patch04 to PennMUSH 1.8.3. After applying this patch, you will have version 1.8.3p4 To apply this patch, save it to a file in your top-level 1.8.3p3 MUSH directory, and do the following: patch -p0 < 1.8.3-patch04 ./configure If you haven't made any changes to src/local.c: cp src/local.dst src/local.c If you have: In your favorite text editor, copy and paste the definition of the local_locks() function from src/local.dst into src/local.c Then: make update make install If you use GNU patch 2.2, you probably want the above to be 'patch -b -p0', not just 'patch -p0'. Unix (or cygwin) users need not worry about failed hunks in src/switchinc.c, hdrs/switches.h, hdrs/cmds.h, or hdrs/funs.h. These files are automatically rebuilt on compile. On the off chance they appear not to be, simply rm them and re-run make. Then @shutdown and restart your MUSH. - Shawn/Raevnos In this patch: Major changes: * Parts of the build process that used a shell script to regenerate certain headers now use perl scripts instead, making them much faster. [SW] Minor changes: * The hash tables used by lmath() and html functions now use perfect hashing to speed up lookups. [SW] * The various slab allocators used by attributes and locks and other areas have been replaced with a generic slab allocator. Also, many more allocations are handled by the new code. * Use the writev() system call to send data to unencrypted connections in bigger chunks instead of using multiple send()s of smaller chunks. * New lock types can be added via src/local.c instead of having to alter the table in src/locks.c. Based on patch by Talvo. * Builtin lock names and default flags are stored in a hash table instead of a list. [SW] Attributes: * @chatformat allows you to customize Channel chat messages that you see. [GM] Commands: * '@list allocations' displays allocation information. * @stats/tables no longer dumps mem_check information. * @search (and by relation search()) now has an 'elock' search class, permitting boolean expression searches. [GM] * @channel/recall extended to support recalling by time. Example: '@chan/recall Foo=1h' will recall lines only from the past hour. Patch by Talvo. Functions: * cond() works like an if, else if, else if ... ncond(), condall(), ncondall() also added. [GM] * speak() accepts a 1st argument beginning with '&' to use an arbitrary speaker name. [GM] * New speakpenn() function handles : in Penn style. Suggested by Sketch, patch by Javeln. * lmath() accepts dist2d and dist3d. Suggested by Jess. * functions(local) returns just local @functions. [SW] * New encode64() and decode64() functions convert between normal text and base64 encoded text on games that have SSL support compiled in. [SW] * encrypt() and decrypt() now take an optional 3rd argument to control using base 64 encoding. Suggested by Noltar. Fixes: * Compile fixes for some linux (And other?) systems that expect all libraries to be after source files on the command line when linking. Reported by Balerion. * Compile fix for some Postgresql installations. Reported by Nymeria. * Fix to fraction() when dealing with numbers that can't be fractioned. Discovered by Ashen-Shugar. * Fixes to align() and coalescing by Javelin. Bugs reported by Sketch and tramp. * Fixes to speak() to bring it closer to Tiny's behavior in common cases by Sketch and Javelin. * Fixes to ANSI output where extra ^[[m were being sent. * Default flags weren't getting set on some attributes in certain cases. Report by Talvo. * Fixes from 1.8.2p6 Prereq: 1.8.3p3 =================================================================== --- Patchlevel (.../p3) (revision 1036) +++ Patchlevel (.../p4) (revision 1036) @@ -1,2 +1,2 @@ Do not edit this file. It is maintained by the official PennMUSH patches. -This is PennMUSH 1.8.3p3 +This is PennMUSH 1.8.3p4 Index: configure =================================================================== --- configure (.../p3) (revision 1036) +++ configure (.../p4) (revision 1036) @@ -7799,7 +7799,8 @@ -for ac_header in sys/un.h ieeefp.h sys/resource.h sys/event.h + +for ac_header in sys/un.h ieeefp.h sys/resource.h sys/event.h sys/uio.h do as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then @@ -13835,9 +13836,14 @@ fi -{ echo "$as_me:$LINENO: checking for fpsetmask" >&5 -echo $ECHO_N "checking for fpsetmask... $ECHO_C" >&6; } -if test "${ac_cv_func_fpsetmask+set}" = set; then + + +for ac_func in fpsetmask fpsetround +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +{ echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; } +if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF @@ -13846,12 +13852,12 @@ cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ -/* Define fpsetmask to an innocuous variant, in case declares fpsetmask. +/* Define $ac_func to an innocuous variant, in case declares $ac_func. For example, HP-UX 11i declares gettimeofday. */ -#define fpsetmask innocuous_fpsetmask +#define $ac_func innocuous_$ac_func /* System header to define __stub macros and hopefully few prototypes, - which can conflict with char fpsetmask (); below. + which can conflict with char $ac_func (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ @@ -13861,7 +13867,7 @@ # include #endif -#undef fpsetmask +#undef $ac_func /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC @@ -13869,18 +13875,18 @@ #ifdef __cplusplus extern "C" #endif -char fpsetmask (); +char $ac_func (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ -#if defined __stub_fpsetmask || defined __stub___fpsetmask +#if defined __stub_$ac_func || defined __stub___$ac_func choke me #endif int main () { -return fpsetmask (); +return $ac_func (); ; return 0; } @@ -13919,84 +13925,46 @@ ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then - ac_cv_func_fpsetmask=yes + eval "$as_ac_var=yes" else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 - ac_cv_func_fpsetmask=no + eval "$as_ac_var=no" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi -{ echo "$as_me:$LINENO: result: $ac_cv_func_fpsetmask" >&5 -echo "${ECHO_T}$ac_cv_func_fpsetmask" >&6; } -if test $ac_cv_func_fpsetmask = yes; then - cat >>confdefs.h <<\_ACEOF -#define HAS_FPSETMASK 1 +ac_res=`eval echo '${'$as_ac_var'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi +done -{ echo "$as_me:$LINENO: checking for fpsetround" >&5 -echo $ECHO_N "checking for fpsetround... $ECHO_C" >&6; } -if test "${ac_cv_func_fpsetround+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -/* Define fpsetround to an innocuous variant, in case declares fpsetround. - For example, HP-UX 11i declares gettimeofday. */ -#define fpsetround innocuous_fpsetround - -/* System header to define __stub macros and hopefully few prototypes, - which can conflict with char fpsetround (); below. - Prefer to if __STDC__ is defined, since - exists even on freestanding compilers. */ - -#ifdef __STDC__ -# include -#else -# include -#endif - -#undef fpsetround - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char fpsetround (); -/* The GNU C library defines this for functions which it implements - to always fail with ENOSYS. Some functions are actually named - something starting with __ and the normal name is an alias. */ -#if defined __stub_fpsetround || defined __stub___fpsetround -choke me -#endif +{ echo "$as_me:$LINENO: checking for isnormal" >&5 +echo $ECHO_N "checking for isnormal... $ECHO_C" >&6; } +cat >conftest.$ac_ext <<_ACEOF -int -main () -{ -return fpsetround (); - ; - return 0; +#include +int main(void) { + return !isnormal(1.0); } + _ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (ac_try="$ac_link" +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_link") 2>conftest.er1 + (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 @@ -14013,7 +13981,7 @@ ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && - { ac_try='test -s conftest$ac_exeext' + { ac_try='test -s conftest.$ac_objext' { (case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; @@ -14023,25 +13991,21 @@ ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then - ac_cv_func_fpsetround=yes + { echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } +cat >>confdefs.h <<\_ACEOF +#define HAVE_ISNORMAL 1 +_ACEOF + else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 - ac_cv_func_fpsetround=no + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -fi -{ echo "$as_me:$LINENO: result: $ac_cv_func_fpsetround" >&5 -echo "${ECHO_T}$ac_cv_func_fpsetround" >&6; } -if test $ac_cv_func_fpsetround = yes; then - cat >>confdefs.h <<\_ACEOF -#define HAS_FPSETROUND 1 -_ACEOF - -fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { echo "$as_me:$LINENO: checking for gai_strerror" >&5 echo $ECHO_N "checking for gai_strerror... $ECHO_C" >&6; } @@ -16131,7 +16095,9 @@ -for ac_func in sigaction sigprocmask imaxdiv kqueue + + +for ac_func in sigaction sigprocmask imaxdiv kqueue valloc writev do as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` { echo "$as_me:$LINENO: checking for $ac_func" >&5 @@ -17365,8 +17331,8 @@ fi done -{ echo "$as_me:$LINENO: checking checking for union wait" >&5 -echo $ECHO_N "checking checking for union wait... $ECHO_C" >&6; } +{ echo "$as_me:$LINENO: checking for union wait" >&5 +echo $ECHO_N "checking for union wait... $ECHO_C" >&6; } { echo "$as_me:$LINENO: checking for union wait" >&5 echo $ECHO_N "checking for union wait... $ECHO_C" >&6; } if test "${ac_cv_type_union_wait+set}" = set; then @@ -17975,7 +17941,7 @@ ac_config_files="$ac_config_files Makefile src/Makefile" -ac_config_files="$ac_config_files utils/mkcmds.sh game/txt/compose.sh" +ac_config_files="$ac_config_files game/txt/compose.sh" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure @@ -18520,7 +18486,6 @@ "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; "src/Makefile") CONFIG_FILES="$CONFIG_FILES src/Makefile" ;; - "utils/mkcmds.sh") CONFIG_FILES="$CONFIG_FILES utils/mkcmds.sh" ;; "game/txt/compose.sh") CONFIG_FILES="$CONFIG_FILES game/txt/compose.sh" ;; *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5 @@ -19067,8 +19032,7 @@ case $ac_file$ac_mode in - "utils/mkcmds.sh":F) chmod +x utils/mkcmds.sh game/txt/compose.sh ;; - "game/txt/compose.sh":F) chmod +x utils/mkcmds.sh game/txt/compose.sh ;; + "game/txt/compose.sh":F) chmod +x game/txt/compose.sh ;; esac done # for ac_tag Index: Makefile.in =================================================================== --- Makefile.in (.../p3) (revision 1036) +++ Makefile.in (.../p4) (revision 1036) @@ -20,8 +20,8 @@ SQL_CFLAGS=@MYSQL_CFLAGS@ @POSTGRESQL_CFLAGS@ @SQLITE3_CFLAGS@ SQL_LDFLAGS=@MYSQL_LDFLAGS@ @POSTGRESQL_LDFLAGS@ @SQLITE3_LDFLAGS@ -CCFLAGS=@CFLAGS@ $(SQL_CFLAGS) -I.. -I../hdrs -LDFLAGS=@LDFLAGS@ $(SQL_LDFLAGS) +CCFLAGS=@CFLAGS@ -I.. -I../hdrs +LDFLAGS=@LDFLAGS@ CLIBS=@LIBS@ INSTALL=@INSTALL@ INSTALLDIR=$installdir @@ -38,7 +38,8 @@ @echo "Making all in src." (cd src; @MAKE@ all "CC=$(CC)" "CCFLAGS=$(CCFLAGS)" \ "LDFLAGS=$(LDFLAGS)" "CLIBS=$(CLIBS)" "MAKE=$(MAKE)" \ - "MAKEFLAGS=$(MAKEFLAGS)") + "MAKEFLAGS=$(MAKEFLAGS)" "SQL_CFLAGS=$(SQL_CFLAGS)" \ + "SQL_LDFLAGS=$(SQL_LDFLAGS)") @echo "If the make was successful, use 'make install' to install links." config.h: configure @@ -56,19 +57,19 @@ autogen: hdrs/cmds.h hdrs/funs.h hdrs/switches.h hdrs/cmds.h: src/cmds.c src/command.c src/cque.c src/help.c src/set.c src/sql.c Patchlevel - (cd utils; sh mkcmds.sh commands) + @PERL@ utils/mkcmds.pl commands hdrs/switches.h: src/SWITCHES Patchlevel - (cd utils; sh mkcmds.sh switches) + @PERL@ utils/mkcmds.pl switches src/switchinc.c: src/SWITCHES Patchlevel - (cd utils; sh mkcmds.sh switches) + @PERL@ utils/mkcmds.pl switches hdrs/funs.h: src/fun*.c src/bsd.c src/conf.c src/extmail.c src/help.c src/markup.c src/wiz.c src/sql.c Patchlevel - (cd utils; sh mkcmds.sh functions) + @PERL@ utils/mkcmds.pl functions hdrs/patches.h: patches/* - (cd utils; sh mkcmds.sh patches) + @PERL@ utils/mkcmds.pl patches install: localized all -rm -f game/netmush Index: options.h.dist =================================================================== --- options.h.dist (.../p3) (revision 1036) +++ options.h.dist (.../p4) (revision 1036) @@ -34,18 +34,14 @@ * 0 -- Use my system's malloc. Required for Win32 systems. * Recommended for FreeBSD, Linux, Mac OS X/Darwin, and other OS's * where you think the malloc routines are efficient and debugged. - * Otherwise, use only as a last resort. - * 1 -- Use the CSRI malloc package in normal mode. - * Recommended for most operating systems where system malloc is - * suspect. Known to work well on SunOS 4.1.x. + * In other words, pretty much any fairly current OS releases. + * 1 -- Use the CSRI malloc package in normal mode. + * Recomended for ancient OS releases. On anything modern, you'll want + * the system malloc (Option 0). * 2 -- Use the CSRI malloc package in debug mode. * Only use this if you're tracking down memory leaks. Don't use * for a production MUSH - it's slow. - * 5 -- Use the GNU malloc (gmalloc) package. - * Doesn't work on Alpha processors or FreeBSD systems, and - * reportedly flaky on Linux. Requires an ANSI compiler. - * Otherwise, similar to CSRI malloc. - * 3, 4, 6 -- Same as 0, kept for compatibility. + * 3, 4, 5, 6 -- Same as 0, kept for compatibility. */ #define MALLOC_PACKAGE 0 Index: Doxyfile =================================================================== --- Doxyfile (.../p3) (revision 1036) +++ Doxyfile (.../p4) (revision 1036) @@ -476,7 +476,8 @@ EXCLUDE = utils \ */obsolete/* \ - */RCS/* + */RCS/* \ + */.svn/* # The EXCLUDE_SYMLINKS tag can be used select whether or not files or # directories that are symbolic links (a Unix filesystem feature) are excluded @@ -524,7 +525,8 @@ # to standard output. If FILTER_PATTERNS is specified, this tag will be # ignored. -INPUT_FILTER = strip_gcc_crap +#INPUT_FILTER = strip_gcc_crap +INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. Doxygen will compare the file name with each pattern and apply the @@ -688,7 +690,7 @@ # The TOC_EXPAND flag can be set to YES to add extra items for group members # to the contents of the HTML help documentation and to the tree view. -TOC_EXPAND = NO +TOC_EXPAND = YES # The DISABLE_INDEX tag can be used to turn on/off the condensed index at # top of each HTML page. The value NO (the default) enables the index and @@ -708,7 +710,7 @@ # Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are # probably better off using the HTML help feature. -GENERATE_TREEVIEW = NO +GENERATE_TREEVIEW = YES # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be # used to set the initial width (in pixels) of the frame in which the tree @@ -723,7 +725,7 @@ # If the GENERATE_LATEX tag is set to YES (the default) Doxygen will # generate Latex output. -GENERATE_LATEX = YES +GENERATE_LATEX = NO # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be Index: hints/mingw32.sh =================================================================== --- hints/mingw32.sh (.../p3) (revision 1036) +++ hints/mingw32.sh (.../p4) (revision 1036) @@ -1,4 +0,0 @@ -cc='gcc' -usenm='n' -libs='-lwsock32' -osname='mingw32' Index: hints/win32-gcc.sh =================================================================== --- hints/win32-gcc.sh (.../p3) (revision 1036) +++ hints/win32-gcc.sh (.../p4) (revision 1036) @@ -1,7 +0,0 @@ -# Hints for win32 with gcc -cc='gcc' -ccflags='-DWIN32' -usenm='n' -h_fcntl='false' -d_ipv6='undef' -d_setlocale='undef' Index: hints/cygwin.sh =================================================================== --- hints/cygwin.sh (.../p3) (revision 1036) +++ hints/cygwin.sh (.../p4) (revision 1036) @@ -1,7 +0,0 @@ -# Hints for cygwin, tested with 1.3.12-2 -# Note that you need the exim-4.10-1 package so you can include -# its minires files -cc='gcc' -ccflags='-I/usr/src/exim-4.10-1/minires' -usenm='y' -d_ipv6='undef' Index: hints/mingw32.txt =================================================================== --- hints/mingw32.txt (.../p3) (revision 0) +++ hints/mingw32.txt (.../p4) (revision 1036) @@ -0,0 +1 @@ +See win32/README.mingw Index: hints/mac_os_x.txt =================================================================== --- hints/mac_os_x.txt (.../p3) (revision 1036) +++ hints/mac_os_x.txt (.../p4) (revision 1036) @@ -30,3 +30,7 @@ or % ./configure --with-postgresql=/sw/bin/pgconfig +Misc. Stuff: + +On PowerPC Macs, consider adding -mdynamic-no-pic to CFLAGS. + Index: hints/windows.txt =================================================================== --- hints/windows.txt (.../p3) (revision 0) +++ hints/windows.txt (.../p4) (revision 1036) @@ -0,0 +1,6 @@ +See the readme files in win32/ + +README.txt for MSVC compilers. +README.cygwin for Cygwin. +README.mingw for MSys. + Index: hints/cygwin.txt =================================================================== --- hints/cygwin.txt (.../p3) (revision 0) +++ hints/cygwin.txt (.../p4) (revision 1036) @@ -0,0 +1 @@ +See win32/README.cygwin Index: src/gmalloc.c =================================================================== --- src/gmalloc.c (.../p3) (revision 1036) +++ src/gmalloc.c (.../p4) (revision 1036) @@ -1,1302 +0,0 @@ -/* DO NOT EDIT THIS FILE -- it is automagically generated. -*- C -*- */ - -#define _MALLOC_INTERNAL - -/* The malloc headers and source files from the C library follow here. */ - -/* Declarations for `malloc' and friends. - Copyright 1990, 1991, 1992, 1993, 1995 Free Software Foundation, Inc. - Written May 1989 by Mike Haertel. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - 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. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; see the file COPYING.LIB. If - not, write to the Free Software Foundation, Inc., 675 Mass Ave, - Cambridge, MA 02139, USA. - - The author may be reached (Email) at the address mike@ai.mit.edu, - or (US mail) as Mike Haertel c/o Free Software Foundation. */ - -#ifndef _MALLOC_H - -#define _MALLOC_H 1 - -#ifdef _MALLOC_INTERNAL - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include - -#ifndef memset -#define memset(s, zero, n) bzero ((s), (n)) -#endif -#ifndef memcpy -#define memcpy(d, s, n) bcopy ((s), (d), (n)) -#endif - - -#if defined (__GNU_LIBRARY__) || (defined (__STDC__) && __STDC__) -#include -#else -#ifndef CHAR_BIT -#define CHAR_BIT 8 -#endif -#endif - -#ifdef HAVE_UNISTD_H -#include -#endif - -#endif /* _MALLOC_INTERNAL. */ - -#ifdef __cplusplus -extern "C" { -#endif - -#if defined (__cplusplus) || (defined (__STDC__) && __STDC__) -#undef __P -#define __P(args) args -#undef __ptr_t -#define __ptr_t void * -#else /* Not C++ or ANSI C. */ -#undef __P -#define __P(args) () -#undef const -#define const -#undef __ptr_t -#define __ptr_t char * -#endif /* C++ or ANSI C. */ - -#if defined (__STDC__) && __STDC__ -#include -#define __malloc_size_t size_t -#define __malloc_ptrdiff_t ptrdiff_t -#else -#define __malloc_size_t unsigned int -#define __malloc_ptrdiff_t int -#endif - -#ifndef NULL -#define NULL 0 -#endif - - -/* Allocate SIZE bytes of memory. */ - extern __ptr_t malloc __P((__malloc_size_t __size)); -/* Re-allocate the previously allocated block - in __ptr_t, making the new block SIZE bytes long. */ - extern __ptr_t realloc __P((__ptr_t __ptr, __malloc_size_t __size)); -/* Allocate NMEMB elements of SIZE bytes each, all initialized to 0. */ - extern __ptr_t calloc __P((__malloc_size_t __nmemb, __malloc_size_t __size)); -/* Free a block allocated by `malloc', `realloc' or `calloc'. */ - extern void free __P((__ptr_t __ptr)); - -/* Allocate SIZE bytes allocated to ALIGNMENT bytes. */ - extern __ptr_t memalign __P((__malloc_size_t __alignment, - __malloc_size_t __size)); - -/* Allocate SIZE bytes on a page boundary. */ - extern __ptr_t valloc __P((__malloc_size_t __size)); - - -#ifdef _MALLOC_INTERNAL - -/* The allocator divides the heap into blocks of fixed size; large - requests receive one or more whole blocks, and small requests - receive a fragment of a block. Fragment sizes are powers of two, - and all fragments of a block are the same size. When all the - fragments in a block have been freed, the block itself is freed. */ -#define INT_BIT (CHAR_BIT * sizeof(int)) -#define BLOCKLOG (INT_BIT > 16 ? 12 : 9) -#define BLOCKSIZE (1 << BLOCKLOG) -#define BLOCKIFY(SIZE) (((SIZE) + BLOCKSIZE - 1) / BLOCKSIZE) - -/* Determine the amount of memory spanned by the initial heap table - (not an absolute limit). */ -#define HEAP (INT_BIT > 16 ? 4194304 : 65536) - -/* Number of contiguous free blocks allowed to build up at the end of - memory before they will be returned to the system. */ -#define FINAL_FREE_BLOCKS 8 - -/* Data structure giving per-block information. */ - typedef union { - /* Heap information for a busy block. */ - struct { - /* Zero for a large (multiblock) object, or positive giving the - logarithm to the base two of the fragment size. */ - int type; - union { - struct { - __malloc_size_t nfree; /* Free frags in a fragmented block. */ - __malloc_size_t first; /* First free fragment of the block. */ - } frag; - /* For a large object, in its first block, this has the number - of blocks in the object. In the other blocks, this has a - negative number which says how far back the first block is. */ - __malloc_ptrdiff_t size; - } info; - } busy; - /* Heap information for a free block - (that may be the first of a free cluster). */ - struct { - __malloc_size_t size; /* Size (in blocks) of a free cluster. */ - __malloc_size_t next; /* Index of next free cluster. */ - __malloc_size_t prev; /* Index of previous free cluster. */ - } free; - } malloc_info; - -/* Pointer to first block of the heap. */ - extern char *_heapbase; - -/* Table indexed by block number giving per-block information. */ - extern malloc_info *_heapinfo; - -/* Address to block number and vice versa. */ -#define BLOCK(A) (((char *) (A) - _heapbase) / BLOCKSIZE + 1) -#define ADDRESS(B) ((__ptr_t) (((B) - 1) * BLOCKSIZE + _heapbase)) - -/* Current search index for the heap table. */ - extern __malloc_size_t _heapindex; - -/* Limit of valid info table indices. */ - extern __malloc_size_t _heaplimit; - -/* Doubly linked lists of free fragments. */ - struct list { - struct list *next; - struct list *prev; - }; - -/* Free list headers for each fragment size. */ - extern struct list _fraghead[]; - -/* List of blocks allocated with `memalign' (or `valloc'). */ - struct alignlist { - struct alignlist *next; - __ptr_t aligned; /* The address that memaligned returned. */ - __ptr_t exact; /* The address that malloc returned. */ - }; - extern struct alignlist *_aligned_blocks; - -/* Instrumentation. */ - extern __malloc_size_t _chunks_used; - extern __malloc_size_t _bytes_used; - extern __malloc_size_t _chunks_free; - extern __malloc_size_t _bytes_free; - -/* Internal version of `free' used in `morecore' (malloc.c). */ - extern void _free_internal __P((__ptr_t __ptr)); - -#endif /* _MALLOC_INTERNAL. */ - -/* Given an address in the middle of a malloc'd object, - return the address of the beginning of the object. */ - extern __ptr_t malloc_find_object_address __P((__ptr_t __ptr)); - -/* Underlying allocation function; successive calls should - return contiguous pieces of memory. */ - extern __ptr_t(*__morecore) __P((__malloc_ptrdiff_t __size)); - -/* Default value of `__morecore'. */ - extern __ptr_t __default_morecore __P((__malloc_ptrdiff_t __size)); - -/* If not NULL, this function is called after each time - `__morecore' is called to increase the data size. */ - extern void (*__after_morecore_hook) __P((void)); - -/* Nonzero if `malloc' has been called and done its initialization. */ - extern int __malloc_initialized; - -/* Hooks for debugging versions. */ - extern void (*__malloc_initialize_hook) __P((void)); - extern void (*__free_hook) __P((__ptr_t __ptr)); - extern __ptr_t(*__malloc_hook) __P((__malloc_size_t __size)); - extern __ptr_t(*__realloc_hook) - __P((__ptr_t __ptr, __malloc_size_t __size)); - extern __ptr_t(*__memalign_hook) - __P((__malloc_size_t __size, __malloc_size_t __alignment)); - -/* Return values for `mprobe': these are the kinds of inconsistencies that - `mcheck' enables detection of. */ - enum mcheck_status { - MCHECK_DISABLED = -1, /* Consistency checking is not turned on. */ - MCHECK_OK, /* Block is fine. */ - MCHECK_FREE, /* Block freed twice. */ - MCHECK_HEAD, /* Memory before the block was clobbered. */ - MCHECK_TAIL /* Memory after the block was clobbered. */ - }; - -/* Activate a standard collection of debugging hooks. This must be called - before `malloc' is ever called. ABORTFUNC is called with an error code - (see enum above) when an inconsistency is detected. If ABORTFUNC is - null, the standard function prints on stderr and then calls `abort'. */ - extern int mcheck __P((void (*__abortfunc) __P((enum mcheck_status)))); - -/* Check for aberrations in a particular malloc'd block. You must have - called `mcheck' already. These are the same checks that `mcheck' does - when you free or reallocate a block. */ - extern enum mcheck_status mprobe __P((__ptr_t __ptr)); - -/* Activate a standard collection of tracing hooks. */ - extern void mtrace __P((void)); - extern void muntrace __P((void)); - -/* Statistics available to the user. */ - struct mstats { - __malloc_size_t bytes_total; /* Total size of the heap. */ - __malloc_size_t chunks_used; /* Chunks allocated by the user. */ - __malloc_size_t bytes_used; /* Byte total of user-allocated chunks. */ - __malloc_size_t chunks_free; /* Chunks in the free list. */ - __malloc_size_t bytes_free; /* Byte total of chunks in the free list. */ - }; - -/* Pick up the current statistics. */ - extern struct mstats mstats __P((void)); - -/* Call WARNFUN with a warning message when memory usage is high. */ - extern void memory_warnings __P((__ptr_t __start, - void (*__warnfun) __P((const char *)))); - - -/* Relocating allocator. */ - -/* Allocate SIZE bytes, and store the address in *HANDLEPTR. */ - extern __ptr_t r_alloc __P((__ptr_t * __handleptr, __malloc_size_t __size)); - -/* Free the storage allocated in HANDLEPTR. */ - extern void r_alloc_free __P((__ptr_t * __handleptr)); - -/* Adjust the block at HANDLEPTR to be SIZE bytes long. */ - extern __ptr_t r_re_alloc - __P((__ptr_t * __handleptr, __malloc_size_t __size)); - - -#ifdef __cplusplus -} -#endif -#endif /* malloc.h */ /* Allocate memory on a page boundary. - Copyright (C) 1991, 1992, 1993, 1994 Free Software Foundation, Inc. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - 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. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; see the file COPYING.LIB. If - not, write to the Free Software Foundation, Inc., 675 Mass Ave, - Cambridge, MA 02139, USA. - - The author may be reached (Email) at the address mike@ai.mit.edu, - or (US mail) as Mike Haertel c/o Free Software Foundation. */ -#if defined (__GNU_LIBRARY__) || defined (_LIBC) -#include -#include -extern size_t __getpagesize __P((void)); -#else -#include "getpgsiz.h" -#define __getpagesize() getpagesize() -#endif -#ifndef _MALLOC_INTERNAL -#define _MALLOC_INTERNAL -#include -#endif -static __malloc_size_t pagesize; - -__ptr_t -valloc(size) - __malloc_size_t size; -{ - if (pagesize == 0) - pagesize = __getpagesize(); - - return memalign(pagesize, size); -} - -/* Memory allocator `malloc'. - Copyright 1990, 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. - Written May 1989 by Mike Haertel. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - 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. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; see the file COPYING.LIB. If - not, write to the Free Software Foundation, Inc., 675 Mass Ave, - Cambridge, MA 02139, USA. - - The author may be reached (Email) at the address mike@ai.mit.edu, - or (US mail) as Mike Haertel c/o Free Software Foundation. */ - -#ifndef _MALLOC_INTERNAL -#define _MALLOC_INTERNAL -#include -#endif - -/* How to really get more memory. */ -__ptr_t(*__morecore) __P((ptrdiff_t __size)) = __default_morecore; - -/* Debugging hook for `malloc'. */ -__ptr_t(*__malloc_hook) __P((__malloc_size_t __size)); - -/* Pointer to the base of the first block. */ - char * - _heapbase; - -/* Block information table. Allocated with align/__free (not malloc/free). */ - malloc_info * - _heapinfo; - -/* Number of info entries. */ - static - __malloc_size_t - heapsize; - -/* Search index in the info table. */ -__malloc_size_t _heapindex; - -/* Limit of valid info table indices. */ -__malloc_size_t _heaplimit; - -/* Free lists for each fragment size. */ - struct list - _fraghead[BLOCKLOG]; - -/* Instrumentation. */ -__malloc_size_t _chunks_used; -__malloc_size_t _bytes_used; -__malloc_size_t _chunks_free; -__malloc_size_t _bytes_free; - -/* Are you experienced? */ - int - __malloc_initialized; - - void (*__malloc_initialize_hook) -__P((void)); - void (*__after_morecore_hook) -__P((void)); - -/* Aligned allocation. */ - static - __ptr_t - align - __P((__malloc_size_t)); - static - __ptr_t - align(size) - __malloc_size_t - size; -{ - __ptr_t result; - unsigned long int adj; - - result = (*__morecore) (size); - adj = (unsigned long int) ((unsigned long int) ((char *) result - - (char *) NULL)) % BLOCKSIZE; - if (adj != 0) { - adj = BLOCKSIZE - adj; - (void) (*__morecore) (adj); - result = (char *) result + adj; - } - if (__after_morecore_hook) - (*__after_morecore_hook) (); - - return result; -} - -/* Set everything up and remember that we have. */ -static int initialize __P((void)); -static int -initialize() -{ - if (__malloc_initialize_hook) - (*__malloc_initialize_hook) (); - - heapsize = HEAP / BLOCKSIZE; - _heapinfo = (malloc_info *) align(heapsize * sizeof(malloc_info)); - if (_heapinfo == NULL) - return 0; - memset(_heapinfo, 0, heapsize * sizeof(malloc_info)); - _heapinfo[0].free.size = 0; - _heapinfo[0].free.next = _heapinfo[0].free.prev = 0; - _heapindex = 0; - _heapbase = (char *) _heapinfo; - - /* Account for the _heapinfo block itself in the statistics. */ - _bytes_used = heapsize * sizeof(malloc_info); - _chunks_used = 1; - - __malloc_initialized = 1; - return 1; -} - -/* Get neatly aligned memory, initializing or - growing the heap info table as necessary. */ -static __ptr_t morecore __P((__malloc_size_t)); -static __ptr_t -morecore(size) - __malloc_size_t size; -{ - __ptr_t result; - malloc_info *newinfo, *oldinfo; - __malloc_size_t newsize; - - result = align(size); - if (result == NULL) - return NULL; - - /* Check if we need to grow the info table. */ - if ((__malloc_size_t) BLOCK((char *) result + size) > heapsize) { - newsize = heapsize; - while ((__malloc_size_t) BLOCK((char *) result + size) > newsize) - newsize *= 2; - newinfo = (malloc_info *) align(newsize * sizeof(malloc_info)); - if (newinfo == NULL) { - (*__morecore) (-size); - return NULL; - } - memcpy(newinfo, _heapinfo, heapsize * sizeof(malloc_info)); - memset(&newinfo[heapsize], 0, (newsize - heapsize) * sizeof(malloc_info)); - oldinfo = _heapinfo; - newinfo[BLOCK(oldinfo)].busy.type = 0; - newinfo[BLOCK(oldinfo)].busy.info.size - = BLOCKIFY(heapsize * sizeof(malloc_info)); - _heapinfo = newinfo; - /* Account for the _heapinfo block itself in the statistics. */ - _bytes_used += newsize * sizeof(malloc_info); - ++_chunks_used; - _free_internal(oldinfo); - heapsize = newsize; - } - _heaplimit = BLOCK((char *) result + size); - return result; -} - -/* Allocate memory from the heap. */ -__ptr_t -malloc(size) - __malloc_size_t size; -{ - __ptr_t result; - __malloc_size_t block, blocks, lastblocks, start; - register __malloc_size_t i; - struct list *next; - - /* ANSI C allows `malloc (0)' to either return NULL, or to return a - valid address you can realloc and free (though not dereference). - - It turns out that some extant code (sunrpc, at least Ultrix's version) - expects `malloc (0)' to return non-NULL and breaks otherwise. - Be compatible. */ - -#if 0 - if (size == 0) - return NULL; -#endif - - if (__malloc_hook != NULL) - return (*__malloc_hook) (size); - - if (!__malloc_initialized) - if (!initialize()) - return NULL; - - if (size < sizeof(struct list)) - size = sizeof(struct list); - -#ifdef SUNOS_LOCALTIME_BUG - if (size < 16) - size = 16; -#endif - - /* Determine the allocation policy based on the request size. */ - if (size <= BLOCKSIZE / 2) { - /* Small allocation to receive a fragment of a block. - Determine the logarithm to base two of the fragment size. */ - register __malloc_size_t log = 1; - --size; - while ((size /= 2) != 0) - ++log; - - /* Look in the fragment lists for a - free fragment of the desired size. */ - next = _fraghead[log].next; - if (next != NULL) { - /* There are free fragments of this size. - Pop a fragment out of the fragment list and return it. - Update the block's nfree and first counters. */ - result = (__ptr_t) next; - next->prev->next = next->next; - if (next->next != NULL) - next->next->prev = next->prev; - block = BLOCK(result); - if (--_heapinfo[block].busy.info.frag.nfree != 0) - _heapinfo[block].busy.info.frag.first = (unsigned long int) - ((unsigned long int) ((char *) next->next - (char *) NULL) - % BLOCKSIZE) >> log; - - /* Update the statistics. */ - ++_chunks_used; - _bytes_used += 1 << log; - --_chunks_free; - _bytes_free -= 1 << log; - } else { - /* No free fragments of the desired size, so get a new block - and break it into fragments, returning the first. */ - result = malloc(BLOCKSIZE); - if (result == NULL) - return NULL; - - /* Link all fragments but the first into the free list. */ - for (i = 1; i < (__malloc_size_t) (BLOCKSIZE >> log); ++i) { - next = (struct list *) ((char *) result + (i << log)); - next->next = _fraghead[log].next; - next->prev = &_fraghead[log]; - next->prev->next = next; - if (next->next != NULL) - next->next->prev = next; - } - - /* Initialize the nfree and first counters for this block. */ - block = BLOCK(result); - _heapinfo[block].busy.type = log; - _heapinfo[block].busy.info.frag.nfree = i - 1; - _heapinfo[block].busy.info.frag.first = i - 1; - - _chunks_free += (BLOCKSIZE >> log) - 1; - _bytes_free += BLOCKSIZE - (1 << log); - _bytes_used -= BLOCKSIZE - (1 << log); - } - } else { - /* Large allocation to receive one or more blocks. - Search the free list in a circle starting at the last place visited. - If we loop completely around without finding a large enough - space we will have to get more memory from the system. */ - blocks = BLOCKIFY(size); - start = block = _heapindex; - while (_heapinfo[block].free.size < blocks) { - block = _heapinfo[block].free.next; - if (block == start) { - /* Need to get more from the system. Check to see if - the new core will be contiguous with the final free - block; if so we don't need to get as much. */ - block = _heapinfo[0].free.prev; - lastblocks = _heapinfo[block].free.size; - if (_heaplimit != 0 && block + lastblocks == _heaplimit && - (*__morecore) (0) == ADDRESS(block + lastblocks) && - (morecore((blocks - lastblocks) * BLOCKSIZE)) != NULL) { - /* Which block we are extending (the `final free - block' referred to above) might have changed, if - it got combined with a freed info table. */ - block = _heapinfo[0].free.prev; - _heapinfo[block].free.size += (blocks - lastblocks); - _bytes_free += (blocks - lastblocks) * BLOCKSIZE; - continue; - } - result = morecore(blocks * BLOCKSIZE); - if (result == NULL) - return NULL; - block = BLOCK(result); - _heapinfo[block].busy.type = 0; - _heapinfo[block].busy.info.size = blocks; - ++_chunks_used; - _bytes_used += blocks * BLOCKSIZE; - return result; - } - } - - /* At this point we have found a suitable free list entry. - Figure out how to remove what we need from the list. */ - result = ADDRESS(block); - if (_heapinfo[block].free.size > blocks) { - /* The block we found has a bit left over, - so relink the tail end back into the free list. */ - _heapinfo[block + blocks].free.size = _heapinfo[block].free.size - blocks; - _heapinfo[block + blocks].free.next = _heapinfo[block].free.next; - _heapinfo[block + blocks].free.prev = _heapinfo[block].free.prev; - _heapinfo[_heapinfo[block].free.prev].free.next - = _heapinfo[_heapinfo[block].free.next].free.prev - = _heapindex = block + blocks; - } else { - /* The block exactly matches our requirements, - so just remove it from the list. */ - _heapinfo[_heapinfo[block].free.next].free.prev - = _heapinfo[block].free.prev; - _heapinfo[_heapinfo[block].free.prev].free.next - = _heapindex = _heapinfo[block].free.next; - --_chunks_free; - } - - _heapinfo[block].busy.type = 0; - _heapinfo[block].busy.info.size = blocks; - ++_chunks_used; - _bytes_used += blocks * BLOCKSIZE; - _bytes_free -= blocks * BLOCKSIZE; - - /* Mark all the blocks of the object just allocated except for the - first with a negative number so you can find the first block by - adding that adjustment. */ - while (--blocks > 0) - _heapinfo[block + blocks].busy.info.size = -blocks; - } - - return result; -} - -#ifndef _LIBC - -/* On some ANSI C systems, some libc functions call _malloc, _free - and _realloc. Make them use the GNU functions. */ - -__ptr_t _malloc _((__malloc_size_t size)); - -__ptr_t -_malloc(size) - __malloc_size_t size; -{ - return malloc(size); -} - -void _free _((__ptr_t ptr)); - -void -_free(ptr) - __ptr_t ptr; -{ - free(ptr); -} - -__ptr_t _realloc _((__ptr_t ptr, size_t size)); - -__ptr_t -_realloc(ptr, size) - __ptr_t ptr; - __malloc_size_t size; -{ - return realloc(ptr, size); -} - -#endif -/* Free a block of memory allocated by `malloc'. - Copyright 1990, 1991, 1992, 1994 Free Software Foundation, Inc. - Written May 1989 by Mike Haertel. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - 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. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; see the file COPYING.LIB. If - not, write to the Free Software Foundation, Inc., 675 Mass Ave, - Cambridge, MA 02139, USA. - - The author may be reached (Email) at the address mike@ai.mit.edu, - or (US mail) as Mike Haertel c/o Free Software Foundation. */ - -#ifndef _MALLOC_INTERNAL -#define _MALLOC_INTERNAL -#include -#endif - -/* Debugging hook for free. */ -void (*__free_hook) __P((__ptr_t __ptr)); - -/* List of blocks allocated by memalign. */ -struct alignlist *_aligned_blocks = NULL; - -/* Return memory to the heap. - Like `free' but don't call a __free_hook if there is one. */ -void -_free_internal(ptr) - __ptr_t ptr; -{ - int type; - __malloc_size_t block, blocks; - register __malloc_size_t i; - struct list *prev, *next; - - block = BLOCK(ptr); - - type = _heapinfo[block].busy.type; - switch (type) { - case 0: - /* Get as many statistics as early as we can. */ - --_chunks_used; - _bytes_used -= _heapinfo[block].busy.info.size * BLOCKSIZE; - _bytes_free += _heapinfo[block].busy.info.size * BLOCKSIZE; - - /* Find the free cluster previous to this one in the free list. - Start searching at the last block referenced; this may benefit - programs with locality of allocation. */ - i = _heapindex; - if (i > block) - while (i > block) - i = _heapinfo[i].free.prev; - else { - do - i = _heapinfo[i].free.next; - while (i > 0 && i < block); - i = _heapinfo[i].free.prev; - } - - /* Determine how to link this block into the free list. */ - if (block == i + _heapinfo[i].free.size) { - /* Coalesce this block with its predecessor. */ - _heapinfo[i].free.size += _heapinfo[block].busy.info.size; - block = i; - } else { - /* Really link this block back into the free list. */ - _heapinfo[block].free.size = _heapinfo[block].busy.info.size; - _heapinfo[block].free.next = _heapinfo[i].free.next; - _heapinfo[block].free.prev = i; - _heapinfo[i].free.next = block; - _heapinfo[_heapinfo[block].free.next].free.prev = block; - ++_chunks_free; - } - - /* Now that the block is linked in, see if we can coalesce it - with its successor (by deleting its successor from the list - and adding in its size). */ - if (block + _heapinfo[block].free.size == _heapinfo[block].free.next) { - _heapinfo[block].free.size - += _heapinfo[_heapinfo[block].free.next].free.size; - _heapinfo[block].free.next - = _heapinfo[_heapinfo[block].free.next].free.next; - _heapinfo[_heapinfo[block].free.next].free.prev = block; - --_chunks_free; - } - /* Now see if we can return stuff to the system. */ - blocks = _heapinfo[block].free.size; - if (blocks >= FINAL_FREE_BLOCKS && block + blocks == _heaplimit - && (*__morecore) (0) == ADDRESS(block + blocks)) { - register __malloc_size_t bytes = blocks * BLOCKSIZE; - _heaplimit -= blocks; - (*__morecore) (-bytes); - _heapinfo[_heapinfo[block].free.prev].free.next - = _heapinfo[block].free.next; - _heapinfo[_heapinfo[block].free.next].free.prev - = _heapinfo[block].free.prev; - block = _heapinfo[block].free.prev; - --_chunks_free; - _bytes_free -= bytes; - } - /* Set the next search to begin at this block. */ - _heapindex = block; - break; - - default: - /* Do some of the statistics. */ - --_chunks_used; - _bytes_used -= 1 << type; - ++_chunks_free; - _bytes_free += 1 << type; - - /* Get the address of the first free fragment in this block. */ - prev = (struct list *) ((char *) ADDRESS(block) + - (_heapinfo[block].busy.info.frag.first << type)); - - if (_heapinfo[block].busy.info.frag.nfree == - (__malloc_size_t) (BLOCKSIZE >> type) - 1) { - /* If all fragments of this block are free, remove them - from the fragment list and free the whole block. */ - next = prev; - for (i = 1; i < (__malloc_size_t) (BLOCKSIZE >> type); ++i) - next = next->next; - prev->prev->next = next; - if (next != NULL) - next->prev = prev->prev; - _heapinfo[block].busy.type = 0; - _heapinfo[block].busy.info.size = 1; - - /* Keep the statistics accurate. */ - ++_chunks_used; - _bytes_used += BLOCKSIZE; - _chunks_free -= BLOCKSIZE >> type; - _bytes_free -= BLOCKSIZE; - - free(ADDRESS(block)); - } else if (_heapinfo[block].busy.info.frag.nfree != 0) { - /* If some fragments of this block are free, link this - fragment into the fragment list after the first free - fragment of this block. */ - next = (struct list *) ptr; - next->next = prev->next; - next->prev = prev; - prev->next = next; - if (next->next != NULL) - next->next->prev = next; - ++_heapinfo[block].busy.info.frag.nfree; - } else { - /* No fragments of this block are free, so link this - fragment into the fragment list and announce that - it is the first free fragment of this block. */ - prev = (struct list *) ptr; - _heapinfo[block].busy.info.frag.nfree = 1; - _heapinfo[block].busy.info.frag.first = (unsigned long int) - ((unsigned long int) ((char *) ptr - (char *) NULL) - % BLOCKSIZE >> type); - prev->next = _fraghead[type].next; - prev->prev = &_fraghead[type]; - prev->prev->next = prev; - if (prev->next != NULL) - prev->next->prev = prev; - } - break; - } -} - -/* Return memory to the heap. */ -void -free(ptr) - __ptr_t ptr; -{ - register struct alignlist *l; - - if (ptr == NULL) - return; - - for (l = _aligned_blocks; l != NULL; l = l->next) - if (l->aligned == ptr) { - l->aligned = NULL; /* Mark the slot in the list as free. */ - ptr = l->exact; - break; - } - if (__free_hook != NULL) - (*__free_hook) (ptr); - else - _free_internal(ptr); -} - -/* Copyright (C) 1991, 1993, 1994 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The GNU C 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. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with the GNU C Library; see the file COPYING.LIB. If - not, write to the Free Software Foundation, Inc., 675 Mass Ave, - Cambridge, MA 02139, USA. */ - -#ifndef _MALLOC_INTERNAL -#define _MALLOC_INTERNAL -#include -#endif - -#ifdef _LIBC - -#include -#include - -#undef cfree - -function_alias(cfree, free, void, (ptr), DEFUN(cfree, (ptr), PTR ptr)) -#else - -void cfree _((__ptr_t ptr)); - -void -cfree(ptr) - __ptr_t ptr; -{ - free(ptr); -} - -#endif -/* Change the size of a block allocated by `malloc'. - Copyright 1990, 1991, 1992, 1993, 1994 Free Software Foundation, Inc. - Written May 1989 by Mike Haertel. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - 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. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; see the file COPYING.LIB. If - not, write to the Free Software Foundation, Inc., 675 Mass Ave, - Cambridge, MA 02139, USA. - - The author may be reached (Email) at the address mike@ai.mit.edu, - or (US mail) as Mike Haertel c/o Free Software Foundation. */ - -#ifndef _MALLOC_INTERNAL -#define _MALLOC_INTERNAL -#include -#endif - -#if (defined (MEMMOVE_MISSING) || \ - !defined(_LIBC) && !defined(STDC_HEADERS) && !defined(USG)) - -/* Snarfed directly from Emacs src/dispnew.c: - XXX Should use system bcopy if it handles overlap. */ -#ifndef emacs - -/* Like bcopy except never gets confused by overlap. */ - -static void -safe_bcopy(from, to, size) - char *from, *to; - int size; -{ - if (size <= 0 || from == to) - return; - - /* If the source and destination don't overlap, then bcopy can - handle it. If they do overlap, but the destination is lower in - memory than the source, we'll assume bcopy can handle that. */ - if (to < from || from + size <= to) - bcopy(from, to, size); - - /* Otherwise, we'll copy from the end. */ - else { - register char *endf = from + size; - register char *endt = to + size; - - /* If TO - FROM is large, then we should break the copy into - nonoverlapping chunks of TO - FROM bytes each. However, if - TO - FROM is small, then the bcopy function call overhead - makes this not worth it. The crossover point could be about - anywhere. Since I don't think the obvious copy loop is too - bad, I'm trying to err in its favor. */ - if (to - from < 64) { - do - *--endt = *--endf; - while (endf != from); - } else { - for (;;) { - endt -= (to - from); - endf -= (to - from); - - if (endt < to) - break; - - bcopy(endf, endt, to - from); - } - - /* If SIZE wasn't a multiple of TO - FROM, there will be a - little left over. The amount left over is - (endt + (to - from)) - to, which is endt - from. */ - bcopy(from, to, endt - from); - } - } -} -#endif /* Not emacs. */ - -#define memmove(to, from, size) safe_bcopy ((from), (to), (size)) - -#endif - - -#define min(A, B) ((A) < (B) ? (A) : (B)) - -/* Debugging hook for realloc. */ -__ptr_t(*__realloc_hook) __P((__ptr_t __ptr, __malloc_size_t __size)); - -/* Resize the given region to the new size, returning a pointer - to the (possibly moved) region. This is optimized for speed; - some benchmarks seem to indicate that greater compactness is - achieved by unconditionally allocating and copying to a - new region. This module has incestuous knowledge of the - internals of both free and malloc. */ -__ptr_t -realloc(ptr, size) - __ptr_t ptr; - __malloc_size_t size; -{ - __ptr_t result; - int type; - __malloc_size_t block, blocks, oldlimit; - - if (size == 0) { - free(ptr); - return malloc(0); - } else if (ptr == NULL) - return malloc(size); - - if (__realloc_hook != NULL) - return (*__realloc_hook) (ptr, size); - - block = BLOCK(ptr); - - type = _heapinfo[block].busy.type; - switch (type) { - case 0: - /* Maybe reallocate a large block to a small fragment. */ - if (size <= BLOCKSIZE / 2) { - result = malloc(size); - if (result != NULL) { - memcpy(result, ptr, size); - _free_internal(ptr); - return result; - } - } - /* The new size is a large allocation as well; - see if we can hold it in place. */ - blocks = BLOCKIFY(size); - if ((__malloc_ptrdiff_t) blocks < _heapinfo[block].busy.info.size) { - /* The new size is smaller; return - excess memory to the free list. */ - _heapinfo[block + blocks].busy.type = 0; - _heapinfo[block + blocks].busy.info.size - = _heapinfo[block].busy.info.size - blocks; - _heapinfo[block].busy.info.size = blocks; - /* We have just created a new chunk by splitting a chunk in two. - Now we will free this chunk; increment the statistics counter - so it doesn't become wrong when _free_internal decrements it. */ - ++_chunks_used; - _free_internal(ADDRESS(block + blocks)); - result = ptr; - } else if ((__malloc_ptrdiff_t) blocks == _heapinfo[block].busy.info.size) - /* No size change necessary. */ - result = ptr; - else { - /* Won't fit, so allocate a new region that will. - Free the old region first in case there is sufficient - adjacent free space to grow without moving. */ - blocks = _heapinfo[block].busy.info.size; - /* Prevent free from actually returning memory to the system. */ - oldlimit = _heaplimit; - _heaplimit = 0; - _free_internal(ptr); - _heaplimit = oldlimit; - result = malloc(size); - if (result == NULL) { - /* Now we're really in trouble. We have to unfree - the thing we just freed. Unfortunately it might - have been coalesced with its neighbors. */ - if (_heapindex == block) - (void) malloc(blocks * BLOCKSIZE); - else { - __ptr_t previous = malloc((block - _heapindex) * BLOCKSIZE); - (void) malloc(blocks * BLOCKSIZE); - _free_internal(previous); - } - return NULL; - } - if (ptr != result) - memmove(result, ptr, blocks * BLOCKSIZE); - } - break; - - default: - /* Old size is a fragment; type is logarithm - to base two of the fragment size. */ - if (size > (__malloc_size_t) (1 << (type - 1)) && - size <= (__malloc_size_t) (1 << type)) - /* The new size is the same kind of fragment. */ - result = ptr; - else { - /* The new size is different; allocate a new space, - and copy the lesser of the new size and the old. */ - result = malloc(size); - if (result == NULL) - return NULL; - memcpy(result, ptr, min(size, (__malloc_size_t) 1 << type)); - free(ptr); - } - break; - } - - return result; -} - -/* Copyright (C) 1991, 1992, 1994 Free Software Foundation, Inc. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - 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. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; see the file COPYING.LIB. If - not, write to the Free Software Foundation, Inc., 675 Mass Ave, - Cambridge, MA 02139, USA. - - The author may be reached (Email) at the address mike@ai.mit.edu, - or (US mail) as Mike Haertel c/o Free Software Foundation. */ - -#ifndef _MALLOC_INTERNAL -#define _MALLOC_INTERNAL -#include -#endif - -/* Allocate an array of NMEMB elements each SIZE bytes long. - The entire array is initialized to zeros. */ -__ptr_t -calloc(nmemb, size) - register __malloc_size_t nmemb; - register __malloc_size_t size; -{ - register __ptr_t result = malloc(nmemb * size); - - if (result != NULL) - (void) memset(result, 0, nmemb * size); - - return result; -} - -/* Copyright (C) 1991, 1992, 1993, 1994 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - The GNU C 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. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with the GNU C Library; see the file COPYING. If not, write to - the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ - -#ifndef _MALLOC_INTERNAL -#define _MALLOC_INTERNAL -#include -#endif - -#ifndef __GNU_LIBRARY__ -#define __sbrk sbrk -#endif - -#ifdef __GNU_LIBRARY__ -/* It is best not to declare this and cast its result on foreign operating - systems with potentially hostile include files. */ -extern __ptr_t __sbrk __P((int increment)); -#endif - -#ifndef NULL -#define NULL 0 -#endif - -/* Allocate INCREMENT more bytes of data space, - and return the start of data space, or NULL on errors. - If INCREMENT is negative, shrink data space. */ -__ptr_t -__default_morecore(increment) -#ifdef __STDC__ - ptrdiff_t increment; -#else - int - increment; -#endif -{ - __ptr_t result = (__ptr_t) __sbrk((int) increment); - if (result == (__ptr_t) - 1) - return NULL; - return result; -} - -/* Copyright (C) 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - 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. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; see the file COPYING.LIB. If - not, write to the Free Software Foundation, Inc., 675 Mass Ave, - Cambridge, MA 02139, USA. */ - -#ifndef _MALLOC_INTERNAL -#define _MALLOC_INTERNAL -#include -#endif - -__ptr_t(*__memalign_hook) __P((size_t __size, size_t __alignment)); - -__ptr_t -memalign(alignment, size) - __malloc_size_t alignment; - __malloc_size_t size; -{ - __ptr_t result; - unsigned long int adj; - - if (__memalign_hook) - return (*__memalign_hook) (alignment, size); - - size = ((size + alignment - 1) / alignment) * alignment; - - result = malloc(size); - if (result == NULL) - return NULL; - adj = (unsigned long int) ((unsigned long int) ((char *) result - - (char *) NULL)) % alignment; - if (adj != 0) { - struct alignlist *l; - for (l = _aligned_blocks; l != NULL; l = l->next) - if (l->aligned == NULL) - /* This slot is free. Use it. */ - break; - if (l == NULL) { - l = (struct alignlist *) malloc(sizeof(struct alignlist)); - if (l == NULL) { - free(result); - return NULL; - } - l->next = _aligned_blocks; - _aligned_blocks = l; - } - l->exact = result; - result = l->aligned = (char *) result + alignment - adj; - } - return result; -} Index: src/mysocket.c =================================================================== --- src/mysocket.c (.../p3) (revision 1036) +++ src/mysocket.c (.../p4) (revision 1036) @@ -374,7 +374,7 @@ fprintf(stderr, "[%d] could not set SO_KEEPALIVE: errno %d", s, errno); /* And set the ping time to something reasonable instead of the - default 2 hours. Linux, NetBSD and o thers use TCP_KEEPIDLE to do + default 2 hours. Linux and possibly others use TCP_KEEPIDLE to do this. OS X and possibly others use TCP_KEEPALIVE. */ #if defined(TCP_KEEPIDLE) if (setsockopt(s, IPPROTO_TCP, TCP_KEEPIDLE, Index: src/fundb.c =================================================================== --- src/fundb.c (.../p3) (revision 1036) +++ src/fundb.c (.../p4) (revision 1036) @@ -1223,8 +1223,8 @@ } ltype = get_locktype(p); - if (GoodObject(it) && (ltype !=NULL) - &&Can_Read_Lock(executor, it, ltype)) { + if (GoodObject(it) && (ltype != NULL) + && Can_Read_Lock(executor, it, ltype)) { ll = getlockstruct(it, ltype); if (ll) { if (fullname) @@ -1262,7 +1262,7 @@ lock_type real_ltype; if ((ltype = strchr(args[0], '/'))) { - *ltype ++ = '\0'; + *ltype++ = '\0'; upcasestr(ltype); } @@ -1306,7 +1306,7 @@ it = match_thing(executor, args[0]); ltype = get_locktype(p); - if (!GoodObject(it) || (ltype == NULL) ||!Can_Read_Lock(executor, it, ltype)) { + if (!GoodObject(it) || (ltype == NULL) || !Can_Read_Lock(executor, it, ltype)) { safe_str("#-1", buff, bp); return; } Index: src/sql.c =================================================================== --- src/sql.c (.../p3) (revision 1036) +++ src/sql.c (.../p4) (revision 1036) @@ -41,7 +41,7 @@ static MYSQL *mysql_connp = NULL; #endif #ifdef HAVE_POSTGRESQL -#include +#include static PGconn *postgres_connp = NULL; #endif #ifdef HAVE_SQLITE3 @@ -608,23 +608,25 @@ default: break; } - if (strchr(cell, ESC_CHAR)) { - /* Old style ANSI string */ - tbp = buffs[i]; - as = parse_ansi_string_real(cell, 1); - safe_ansi_string(as, 0, as->len, buffs[i], &tbp); - *tbp = '\0'; - free_ansi_string(as); - cell = buffs[i]; - } else if (strchr(cell, TAG_START)) { - /* Either old or new style ANSI string, - * We assume new style. */ - tbp = buffs[i]; - as = parse_ansi_string_real(cell, 2); - safe_ansi_string(as, 0, as->len, buffs[i], &tbp); - *tbp = '\0'; - free_ansi_string(as); - cell = buffs[i]; + if (cell) { + if (strchr(cell, ESC_CHAR)) { + /* Old style ANSI string */ + tbp = buffs[i]; + as = parse_ansi_string_real(cell, 1); + safe_ansi_string(as, 0, as->len, buffs[i], &tbp); + *tbp = '\0'; + free_ansi_string(as); + cell = buffs[i]; + } else if (strchr(cell, TAG_START)) { + /* Either old or new style ANSI string, + * We assume new style. */ + tbp = buffs[i]; + as = parse_ansi_string_real(cell, 2); + safe_ansi_string(as, 0, as->len, buffs[i], &tbp); + *tbp = '\0'; + free_ansi_string(as); + cell = buffs[i]; + } } wenv[i + 1] = cell; if (!wenv[i + 1]) Index: src/extchat.c =================================================================== --- src/extchat.c (.../p3) (revision 1036) +++ src/extchat.c (.../p4) (revision 1036) @@ -38,8 +38,8 @@ static CHAN *new_channel(void); -static CHANLIST *new_chanlist(void); -static CHANUSER *new_user(dbref who); +static CHANLIST *new_chanlist(const void *hint); +static CHANUSER *new_user(dbref who, const void *hint); static void free_channel(CHAN *c); static void free_chanlist(CHANLIST *cl); static void free_user(CHANUSER *u); @@ -72,9 +72,8 @@ static void do_channel_who(dbref player, CHAN *chan); void chat_player_announce(dbref player, char *msg, int ungag); static int ok_channel_name(const char *n); -static void format_channel_broadcast(CHAN *chan, CHANUSER *u, dbref victim, - int flags, const char *msg, - const char *extra); +static void format_channel_chat(CHAN *chan, CHANUSER *u, dbref victim, + int flags, const char *msg, const char *extra); static void list_partial_matches(dbref player, const char *name, enum chan_match_type type); @@ -84,13 +83,17 @@ const char *chan_see_lock = "ChanSeeLock"; /**< Name of see lock */ const char *chan_hide_lock = "ChanHideLock"; /**< Name of hide lock */ +slab *channel_slab; /**< slab for 'struct channel' allocations */ +slab *chanlist_slab; /**< slab for 'struct chanlist' allocations */ +slab *chanuser_slab; /**< slab for 'struct chanuser' allocations */ + #define YES 1 /**< An affirmative. */ #define NO 0 /**< A negative. */ #define ERR -1 /**< An error. Clever, eh? */ /** Wrapper for insert_user() that generates a new CHANUSER and inserts it */ #define insert_user_by_dbref(who,chan) \ - insert_user(new_user(who),chan) + insert_user(new_user(who, ChanUsers(chan)),chan) /** Wrapper for remove_user() that searches for the CHANUSER to remove */ #define remove_user_by_dbref(who,chan) \ remove_user(onchannel(who,chan),chan) @@ -193,6 +196,11 @@ init_chatdb(void) { num_channels = 0; + channel_slab = slab_create("channels", sizeof(struct channel)); + chanuser_slab = slab_create("channel users", sizeof(struct chanuser)); + chanlist_slab = slab_create("channel lists", sizeof(struct chanlist)); + slab_set_opt(chanuser_slab, SLAB_ALLOC_BEST_FIT, 1); + slab_set_opt(chanlist_slab, SLAB_ALLOC_BEST_FIT, 1); channels = NULL; } @@ -315,7 +323,7 @@ { CHAN *ch; - ch = (CHAN *) mush_malloc(sizeof(CHAN), "CHAN"); + ch = slab_malloc(channel_slab, NULL); if (!ch) return NULL; ch->name[0] = '\0'; @@ -342,10 +350,10 @@ /* Malloc memory for a new user, and initialize it */ static CHANUSER * -new_user(dbref who) +new_user(dbref who, const void *hint) { CHANUSER *u; - u = (CHANUSER *) mush_malloc(sizeof(CHANUSER), "CHANUSER"); + u = slab_malloc(chanuser_slab, hint); if (!u) mush_panic("Couldn't allocate memory in new_user in extchat.c"); CUdbref(u) = who; @@ -381,7 +389,7 @@ free_user(CHANUSER *u) { if (u) - mush_free(u, "CHANUSER"); + slab_free(chanuser_slab, u); } /* Load in a single channel into position i. Return 1 if @@ -390,10 +398,10 @@ static int load_channel(FILE * fp, CHAN *ch) { - strcpy(ChanName(ch), getstring_noalloc(fp)); + mush_strncpy(ChanName(ch), getstring_noalloc(fp), CHAN_NAME_LEN); if (feof(fp)) return 0; - strcpy(ChanTitle(ch), getstring_noalloc(fp)); + mush_strncpy(ChanTitle(ch), getstring_noalloc(fp), CHAN_TITLE_LEN); ChanType(ch) = (privbits) getref(fp); ChanCreator(ch) = getref(fp); ChanCost(ch) = getref(fp); @@ -423,9 +431,9 @@ char *label, *value; db_read_this_labeled_string(fp, "name", &tmp); - strcpy(ChanName(ch), tmp); + mush_strncpy(ChanName(ch), tmp, CHAN_NAME_LEN); db_read_this_labeled_string(fp, "description", &tmp); - strcpy(ChanTitle(ch), tmp); + mush_strncpy(ChanTitle(ch), tmp, CHAN_TITLE_LEN); db_read_this_labeled_int(fp, "flags", &i); ChanType(ch) = (privbits) i; db_read_this_labeled_dbref(fp, "creator", &d); @@ -468,7 +476,7 @@ player = getref(fp); /* Don't bother if the player isn't a valid dbref or the wrong type */ if (GoodObject(player) && Chan_Ok_Type(ch, player)) { - user = new_user(player); + user = new_user(player, ChanUsers(ch)); CUtype(user) = getref(fp); strcpy(CUtitle(user), getstring_noalloc(fp)); CUnext(user) = NULL; @@ -497,11 +505,11 @@ db_read_this_labeled_dbref(fp, "dbref", &player); /* Don't bother if the player isn't a valid dbref or the wrong type */ if (GoodObject(player) && Chan_Ok_Type(ch, player)) { - user = new_user(player); + user = new_user(player, ChanUsers(ch)); db_read_this_labeled_int(fp, "flags", &n); CUtype(user) = n; db_read_this_labeled_string(fp, "title", &tmp); - strcpy(CUtitle(user), tmp); + mush_strncpy(CUtitle(user), tmp, CU_TITLE_LEN); CUnext(user) = NULL; if (insert_user(user, ch)) num++; @@ -593,7 +601,7 @@ if (!ch || !*ch) return; - tmp = new_chanlist(); + tmp = new_chanlist(Chanlist(who)); if (!tmp) return; tmp->chan = *ch; @@ -675,10 +683,10 @@ static CHANLIST * -new_chanlist(void) +new_chanlist(const void *hint) { CHANLIST *c; - c = (CHANLIST *) mush_malloc(sizeof(CHANLIST), "CHANLIST"); + c = slab_malloc(chanlist_slab, hint); if (!c) return NULL; c->chan = NULL; @@ -689,7 +697,7 @@ static void free_chanlist(CHANLIST *cl) { - mush_free(cl, "CHANLIST"); + slab_free(chanlist_slab, cl); } @@ -716,7 +724,7 @@ p = p->next) ; if (CUdbref(p) == CUdbref(user)) { /* Don't add the same user twice! */ - mush_free((Malloc_t) user, "CHANUSER"); + slab_free(chanuser_slab, user); return 0; } else { user->next = p->next; @@ -1227,8 +1235,8 @@ ChanName(chan)); u = onchannel(victim, chan); if (!Channel_Quiet(chan) && !DarkLegal(victim)) { - format_channel_broadcast(chan, u, victim, CB_CHECKQUIET | CB_PRESENCE, - T("<%s> %s has joined this channel."), NULL); + format_channel_chat(chan, u, victim, CB_CHECKQUIET | CB_PRESENCE, + T("%s has joined this channel."), NULL); } ChanNumUsers(chan)++; } else { @@ -1252,9 +1260,9 @@ strcpy(title, (u && CUtitle(u)) ? CUtitle(u) : ""); if (remove_user(u, chan)) { if (!Channel_Quiet(chan) && !DarkLegal(victim)) { - format_channel_broadcast(chan, NULL, victim, - CB_CHECKQUIET | CB_PRESENCE, - T("<%s> %s has left this channel."), title); + format_channel_chat(chan, NULL, victim, + CB_CHECKQUIET | CB_PRESENCE, + T("%s has left this channel."), title); } notify_format(victim, T("CHAT: %s removes you from channel <%s>."), @@ -1325,8 +1333,8 @@ notify_format(player, T("CHAT: You join channel <%s>."), ChanName(chan)); u = onchannel(player, chan); if (!Channel_Quiet(chan) && !DarkLegal(player)) - format_channel_broadcast(chan, u, player, CB_CHECKQUIET | CB_PRESENCE, - T("<%s> %s has joined this channel."), NULL); + format_channel_chat(chan, u, player, CB_CHECKQUIET | CB_PRESENCE, + T("%s has joined this channel."), NULL); ChanNumUsers(chan)++; } else { /* Should never happen */ @@ -1367,8 +1375,8 @@ strcpy(title, (u && CUtitle(u)) ? CUtitle(u) : ""); if (remove_user(u, chan)) { if (!Channel_Quiet(chan) && !DarkLegal(player)) - format_channel_broadcast(chan, NULL, player, CB_CHECKQUIET | CB_PRESENCE, - T("<%s> %s has left this channel."), title); + format_channel_chat(chan, NULL, player, CB_CHECKQUIET | CB_PRESENCE, + T("%s has left this channel."), title); notify_format(player, T("CHAT: You leave channel <%s>."), ChanName(chan)); } else { /* Should never happen */ @@ -1488,6 +1496,7 @@ { CHANUSER *u; const char *gap; + char type; const char *someone = "Someone"; char *title; const char *name; @@ -1540,15 +1549,17 @@ /* figure out what kind of message we have */ gap = " "; + type = ':'; switch (*arg1) { case SEMI_POSE_TOKEN: gap = ""; + type = ';'; /* FALLTHRU */ case POSE_TOKEN: arg1 = arg1 + 1; - channel_broadcast(chan, player, 0, "<%s> %s%s%s%s%s%s", ChanName(chan), - title ? title : "", title ? ANSI_ENDALL : "", - (title && name) ? " " : "", name ? name : "", gap, arg1); + channel_chat(chan, player, 0, arg1, type, "<%s> %s%s%s%s%s%s", + ChanName(chan), title ? title : "", title ? ANSI_ENDALL : "", + (title && name) ? " " : "", name ? name : "", gap, arg1); if (!canhear) notify_format(player, T("To channel %s: %s%s%s%s%s%s"), ChanName(chan), title ? title : "", title ? ANSI_ENDALL : "", @@ -1557,10 +1568,10 @@ default: if (CHAT_STRIP_QUOTE && (*arg1 == SAY_TOKEN)) arg1 = arg1 + 1; - channel_broadcast(chan, player, 0, T("<%s> %s%s%s%s says, \"%s\""), - ChanName(chan), title ? title : "", - title ? ANSI_ENDALL : "", (title && name) ? " " : "", - name ? name : "", arg1); + channel_chat(chan, player, 0, arg1, '"', T("<%s> %s%s%s%s says, \"%s\""), + ChanName(chan), title ? title : "", + title ? ANSI_ENDALL : "", (title && name) ? " " : "", + name ? name : "", arg1); if (!canhear) notify_format(player, T("To channel %s: %s%s%s%s says, \"%s\""), @@ -1646,11 +1657,11 @@ return; } if (!(flags & PEMIT_SILENT)) - channel_broadcast(chan, player, (flags & PEMIT_SPOOF) ? 0 : CB_NOSPOOF, - "<%s> %s", ChanName(chan), msg); + channel_chat(chan, player, (flags & PEMIT_SPOOF) ? 0 : CB_NOSPOOF, + msg, '|', "<%s> %s", ChanName(chan), msg); else - channel_broadcast(chan, player, (flags & PEMIT_SPOOF) ? 0 : CB_NOSPOOF, - "%s", msg); + channel_chat(chan, player, (flags & PEMIT_SPOOF) ? 0 : CB_NOSPOOF, + msg, '|', "%s", msg); if (!canhear) notify_format(player, T("Cemit to channel %s: %s"), ChanName(chan), msg); ChanNumMsgs(chan)++; @@ -1675,6 +1686,7 @@ int res; boolexp key; char old[CHAN_NAME_LEN]; + char announcebuff[BUFFER_LEN]; if (!name || !*name) { notify(player, T("You must specify a channel.")); @@ -1742,7 +1754,7 @@ } key = parse_boolexp(player, tprintf("=#%d", player), chan_mod_lock); if (!key) { - mush_free(chan, "CHAN"); + slab_free(channel_slab, chan); notify(player, T("CHAT: No more memory for channels!")); giveto(Owner(player), CHANNEL_COST); return; @@ -1799,9 +1811,11 @@ remove_channel(chan); strcpy(ChanName(chan), perms); insert_channel(&chan); - channel_broadcast(chan, player, 0, - "<%s> %s has renamed channel %s to %s.", - ChanName(chan), Name(player), old, ChanName(chan)); + snprintf(announcebuff, BUFFER_LEN, "has renamed %s to %s", + old, ChanName(chan)); + channel_chat(chan, player, 0, announcebuff, '@', + "<%s> %s has renamed channel %s to %s.", + ChanName(chan), Name(player), old, ChanName(chan)); notify(player, T("Channel renamed.")); break; case 3: @@ -2867,19 +2881,14 @@ { CHAN *c; CHANUSER *u; - char buff[BUFFER_LEN], *bp; for (c = channels; c; c = c->next) { u = onchannel(player, c); if (u) { if (!Channel_Quiet(c) && (Channel_Admin(c) || Channel_Wizard(c) || (!Chanuser_Hide(u) && !Dark(player)))) { - bp = buff; - - safe_format(buff, &bp, "<%s> %s", "%s", msg); - *bp = '\0'; - format_channel_broadcast(c, u, player, CB_CHECKQUIET | CB_PRESENCE, - buff, NULL); + format_channel_chat(c, u, player, CB_CHECKQUIET | CB_PRESENCE, + msg, NULL); } if (ungag) CUtype(u) &= ~CU_GAG; @@ -3061,7 +3070,9 @@ { CHAN *chan; CHANUSER *u; - int start = -1, num_lines = 10; + int start = -1, num_lines; + bool recall_timestring = false; + time_t recall_from = 0; char *p = NULL, *buf, *name; time_t timestamp; char *stamp; @@ -3078,11 +3089,14 @@ } if (!args[1] || !*args[1]) { - /* nothing */ + num_lines = 10; /* default */ } else if (is_integer(args[1])) { num_lines = parse_integer(args[1]); if (num_lines == 0) num_lines = INT_MAX; + } else if (etime_to_secs(args[1], &num_lines)) { + recall_timestring = 1; + recall_from = (time_t) mudtime - num_lines; } else { safe_str(T(e_int), buff, bp); return; @@ -3127,6 +3141,15 @@ return; } + if (recall_timestring) { + num_lines = 0; + while ((buf = + iter_bufferq(ChanBufferQ(chan), &p, &speaker, &type, ×tamp))) { + if (timestamp >= recall_from) + num_lines++; + } + p = NULL; + } if (start < 0) start = BufferQNum(ChanBufferQ(chan)) - num_lines; if (isempty_bufferq(ChanBufferQ(chan)) @@ -3278,14 +3301,16 @@ return current; } -/** Broadcast a message to a channel. +/** Broadcast a message to a channel, using @chatformat if it's + * available. * \param channel pointer to channel to broadcast to. * \param player message speaker. * \param flags broadcast flag mask (see CB_* constants in extchat.h) * \param fmt message format string. */ void WIN32_CDECL -channel_broadcast(CHAN *channel, dbref player, int flags, const char *fmt, ...) +channel_chat(CHAN *channel, dbref player, int flags, + const char *message, char type, const char *fmt, ...) /* flags: 0x1 = checkquiet, 0x2 = nospoof */ { va_list args; @@ -3294,8 +3319,17 @@ #else char tbuf1[BUFFER_LEN * 2]; /* Safety margin as per tprintf */ #endif - struct na_cpass nac; + CHANUSER *u; + dbref current; + const char *cname; + const char *name, *title; + char ctype[2]; + char ctitle[CU_TITLE_LEN]; int na_flags = NA_INTER_LOCK; + const char *someone = "Someone"; + + ctype[0] = type; + ctype[1] = '\0'; /* Make sure we can write to the channel before doing so */ if (Channel_Disabled(channel)) @@ -3311,12 +3345,39 @@ va_end(args); tbuf1[BUFFER_LEN - 1] = '\0'; - nac.u = ChanUsers(channel); - nac.checkquiet = (flags & CB_CHECKQUIET) ? 1 : 0; + cname = ChanName(channel); + u = onchannel(player, channel); + strcpy(ctitle, (u && CUtitle(u)) ? CUtitle(u) : ""); + + if (!Channel_NoTitles(channel) || !*ctitle) + title = ctitle; + else + title = NULL; + if (Channel_NoNames(channel)) + name = NULL; + else + name = accented_name(player); + if (!title && !name) + name = someone; + if (Channel_Interact(channel)) na_flags |= (flags & CB_PRESENCE) ? NA_INTER_PRESENCE : NA_INTER_HEAR; - notify_anything(player, na_channel, &nac, ns_esnotify, - na_flags | ((flags & CB_NOSPOOF) ? 0 : NA_SPOOF), tbuf1); + + for (u = ChanUsers(channel); u; u = u->next) { + current = CUdbref(u); + + if (!(((flags & 1) && Chanuser_Quiet(u)) || + Chanuser_Gag(u) || (IsPlayer(current) && !Connected(current)))) { + if (!messageformat(current, "CHATFORMAT", player, + na_flags | ((flags & CB_NOSPOOF) ? 0 : NA_SPOOF), + ctype, cname, message, name, title, tbuf1)) { + notify_anything(player, na_one, ¤t, ns_esnotify, + na_flags | ((flags & CB_NOSPOOF) ? 0 : NA_SPOOF), + tbuf1); + } + } + } + if (ChanBufferQ(channel)) add_to_bufferq(ChanBufferQ(channel), 0, (flags & CB_NOSPOOF) ? player : NOTHING, tbuf1); @@ -3339,10 +3400,12 @@ { CHAN *chan; CHANUSER *u; - const char *lines; + char *lines; const char *startpos; - int num_lines = 10; /* Default if none is given */ + int num_lines; int start = -1; + time_t recall_from = 0; + bool recall_timestring = false; int all; char *p = NULL, *buf; time_t timestamp; @@ -3367,11 +3430,17 @@ num_lines = parse_integer(lines); if (num_lines == 0) num_lines = INT_MAX; + } else if (etime_to_secs(lines, &num_lines)) { + recall_timestring = 1; + recall_from = (time_t) mudtime - num_lines; } else { notify(player, T("How many lines did you want to recall?")); return; } + } else { + num_lines = 10; /* default value */ } + if (num_lines < 1) { notify(player, T("How many lines did you want to recall?")); return; @@ -3396,6 +3465,15 @@ notify(player, T("CHAT: That channel doesn't have a recall buffer.")); return; } + if (recall_timestring) { + num_lines = 0; + while ((buf = + iter_bufferq(ChanBufferQ(chan), &p, &speaker, &type, ×tamp))) { + if (timestamp >= recall_from) + num_lines++; + } + p = NULL; + } if (start < 0) start = BufferQNum(ChanBufferQ(chan)) - num_lines; if (isempty_bufferq(ChanBufferQ(chan)) @@ -3403,7 +3481,6 @@ notify(player, T("CHAT: Nothing to recall.")); return; } - all = (start <= 0 && num_lines >= BufferQNum(ChanBufferQ(chan))); notify_format(player, T("CHAT: Recall from channel <%s>"), ChanName(chan)); while (start > 0) { @@ -3505,22 +3582,27 @@ /* msg is a printf-style format that has exactly and only 2 %s specifiers in it. */ static void -format_channel_broadcast(CHAN *chan, CHANUSER *u, - dbref victim, int flags, - const char *msg, const char *extra) +format_channel_chat(CHAN *chan, CHANUSER *u, + dbref victim, int flags, const char *msg, const char *extra) { const char *title = NULL; + char fmtbuff[BUFFER_LEN]; if (extra && *extra) title = extra; else if (u && CUtitle(u)) title = CUtitle(u); if (Channel_NoNames(chan)) { - if (Channel_NoTitles(chan) || !title) - channel_broadcast(chan, victim, flags, msg, ChanName(chan), "Someone"); - else - channel_broadcast(chan, victim, flags, msg, ChanName(chan), title); - } else - channel_broadcast(chan, victim, flags, msg, ChanName(chan), Name(victim)); + if (Channel_NoTitles(chan) || !title) { + channel_chat(chan, victim, flags, msg, '@', ChanName(chan), "Someone"); + snprintf(fmtbuff, BUFFER_LEN, msg, "Someone"); + } else { + snprintf(fmtbuff, BUFFER_LEN, msg, title); + } + } else { + snprintf(fmtbuff, BUFFER_LEN, msg, Name(victim)); + } + channel_chat(chan, victim, flags, fmtbuff, '@', "<%s> %s", + ChanName(chan), fmtbuff); } Index: src/utils.c =================================================================== --- src/utils.c (.../p3) (revision 1036) +++ src/utils.c (.../p4) (revision 1036) @@ -52,64 +52,10 @@ dbref find_entrance(dbref door); void initialize_mt(void); -static unsigned long genrand_int32(void); +uint32_t genrand_int32(void); static void init_genrand(unsigned long); static void init_by_array(unsigned long *, int); -/** 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. - * \param size bytes to allocate. - * \param check string to label allocation with. - * \return allocated block of memory or NULL. - */ -void * -mush_malloc(size_t bytes, const char *check) -{ - void *ptr; - ptr = malloc(bytes); - if (!ptr) - do_log(LT_ERR, 0, 0, "mush_malloc failed to malloc %lu bytes for %s", - (unsigned long) bytes, check); - add_check(check); - return ptr; -} - -/** A calloc wrapper that tracks type of allocation. - * Use in preference to calloc() when possible to enable - * memory leak checking. - * \param count number of elements to allocate - * \param size size of each element - * \param check string to label allocation with - * \return allocated zeroed out block or NULL - */ -void * -mush_calloc(size_t count, size_t size, const char *check) -{ - void *ptr; - - ptr = calloc(count, size); - if (!ptr) - do_rawlog(LT_ERR, "mush_calloc failed to allocate %lu bytes for %s", - (unsigned long) (size * count), check); - add_check(check); - return ptr; -} - -/** A free wrapper that tracks type of allocation. - * If mush_malloc() gets the memory, mush_free() should free it - * to enable memory leak tracing with MEM_CHECK. - * \param ptr pointer to block of member to free. - * \param check string to label allocation with. - */ -void -mush_free(void *RESTRICT ptr, const char *RESTRICT check) -{ - del_check(check); - free(ptr); - return; -} - /** Parse object/attribute strings into components. * This function takes a string which is of the format obj/attr or attr, @@ -164,9 +110,10 @@ } else { *attrib = mush_malloc(sizeof(ATTR), "anon_attr"); AL_CREATOR(*attrib) = player; - AL_NAME(*attrib) = strdup("#lambda"); + AL_NAME(*attrib) = mush_strdup("#lambda", "anon_attr.lambda"); t = compress(str); (*attrib)->data = chunk_create(t, u_strlen(t), 0); + free(t); AL_FLAGS(*attrib) = AF_ANON; AL_NEXT(*attrib) = NULL; *thing = player; @@ -183,7 +130,7 @@ free_anon_attrib(ATTR *attrib) { if (attrib && (AL_FLAGS(attrib) & AF_ANON)) { - free((char *) AL_NAME(attrib)); + mush_free((void *) AL_NAME(attrib), "anon_attr.lambda"); chunk_delete(attrib->data); mush_free(attrib, "anon_attr"); } @@ -192,10 +139,15 @@ /** Given an attribute [/] pair (which may include #lambda), * fetch its value, owner (thing), and pe_flags, and store in the struct * pointed to by ufun + * \param attrname The obj/name of attribute. + * \param executor Dbref of the executing object. + * \param ufun Pointer to an allocated ufun_attrib struct to fill in. + * \param accept_lambda true if #lambda can be used. + * \return 0 on failure, true on success. */ -int +bool fetch_ufun_attrib(char *attrname, dbref executor, ufun_attrib * ufun, - int accept_lambda) + bool accept_lambda) { ATTR *attrib; dbref thing; @@ -267,7 +219,7 @@ * \retval 0 success * \retval 1 process_expression failed. (CPU time limit) */ -int +bool call_ufun(ufun_attrib * ufun, char **wenv_args, int wenv_argc, char *ret, dbref executor, dbref enactor, PE_Info *pe_info) { @@ -354,9 +306,9 @@ * \param enactor The enactor. * \param pe_info The pe_info passed to the FUNCTION * \retval 0 success - * \retval 1 process_expression failed. (CPU time limit) + * \retval 1 No such attribute, or failed. */ -int +bool call_attrib(dbref thing, const char *attrname, const char *wenv_args[], int wenv_argc, char *ret, dbref enactor, PE_Info *pe_info) { @@ -389,8 +341,11 @@ mush_strncpy(atrbuf, atr_value(attrib), BUFFER_LEN); - if (!*atrbuf) - return 1; + if (!*atrbuf) { + if (ret) + *ret = '\0'; + return 0; + } save_global_regs("localize", saver); @@ -510,7 +465,7 @@ * \retval 1 found thing on list. * \retval 0 did not find thing on list. */ -int +bool member(dbref thing, dbref list) { DOLIST(list, list) { @@ -533,7 +488,7 @@ * \retval 1 disallow is inside of from. * \retval 0 disallow is not inside of from. */ -int +bool recursive_member(dbref disallow, dbref from, int count) { do { @@ -556,7 +511,7 @@ * \retval 1 object or location is unfindable. * \retval 0 neither object nor location is unfindable. */ -int +bool unfindable(dbref thing) { int count = 0; @@ -726,7 +681,7 @@ } /* generates a random number on [0,0xffffffff]-interval */ -static unsigned long +uint32_t genrand_int32(void) { unsigned long y; @@ -825,8 +780,10 @@ static char n[BUFFER_LEN]; /* STATIC */ ATTR *a = atr_get_noparent(it, "ALIAS"); - if (!a) - return '\0'; + if (!a) { + n[0] = '\0'; + return n; + } mush_strncpy(n, atr_value(a), BUFFER_LEN); @@ -845,8 +802,10 @@ char *s; s = fullalias(it); - if (!(s && *s)) - return '\0'; + if (!(s && *s)) { + n[0] = '\0'; + return n; + } mush_strncpy(n, s, BUFFER_LEN); if ((s = strchr(n, ';'))) Index: src/Makefile.in =================================================================== --- src/Makefile.in (.../p3) (revision 1036) +++ src/Makefile.in (.../p4) (revision 1036) @@ -6,51 +6,38 @@ OUTFILES=buildinf netmud info_slave -# stupid SYS V shell - -# for lint target -LINT=lint -LINTFLAGS=-haz $(DEFINES) -LINTFILT=egrep -v '(possible pointer|long assign|not yet im|:$$)' - -# Libs -LIBS=$(CLIBS) $(RLIBS) $(ILIBS) - -CFLAGS=$(CCFLAGS) $(RDEFS) $(IDEFS) +# Libs EXCEPT for SQL ones +LIBS=$(CLIBS) -# Used for protoizing -#.c.o: -# $(CC) $(CFLAGS) -aux-info $<.X -c $< +CFLAGS=$(CCFLAGS) $(SQL_CFLAGS) # List of C files, used for make depend: -C_FILES=access.c atr_tab.c attrib.c boolexp.c bsd.c bufferq.c \ - chunk.c cmdlocal.c cmds.c \ - command.c compress.c conf.c cque.c create.c db.c destroy.c extchat.c \ - extmail.c filecopy.c flaglocal.c flags.c funcrypt.c function.c \ - fundb.c funlist.c funlocal.c funmath.c funmisc.c funstr.c funtime.c \ - funufun.c game.c help.c htab.c ident.c local.c lock.c log.c look.c \ - malias.c markup.c match.c memcheck.c move.c mycrypt.c mymalloc.c \ - mysocket.c myrlimit.c myssl.c notify.c parse.c pcre.c player.c \ - plyrlist.c predicat.c privtab.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 \ +C_FILES=access.c atr_tab.c attrib.c boolexp.c bsd.c bufferq.c chunk.c \ + cmdlocal.c cmds.c command.c compress.c conf.c cque.c create.c \ + db.c destroy.c extchat.c extmail.c filecopy.c flaglocal.c \ + flags.c funcrypt.c function.c fundb.c funlist.c funlocal.c \ + funmath.c funmisc.c funstr.c funtime.c funufun.c game.c help.c \ + htab.c ident.c local.c lock.c log.c look.c malias.c markup.c \ + match.c memcheck.c move.c mycrypt.c mymalloc.c mysocket.c \ + myrlimit.c myssl.c notify.c parse.c pcre.c player.c plyrlist.c \ + predicat.c privtab.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 # .o versions of above - these are used in the build -O_FILES=access.o atr_tab.o attrib.o boolexp.o bsd.o bufferq.o \ - chunk.o cmdlocal.o cmds.o \ - command.o compress.o conf.o cque.o create.o db.o destroy.o extchat.o \ - extmail.o filecopy.o flaglocal.o flags.o funcrypt.o function.o \ - fundb.o funlist.o funlocal.o funmath.o funmisc.o funstr.o funtime.o \ - funufun.o game.o help.o htab.o ident.o local.o lock.o log.o look.o \ - malias.o markup.o match.o memcheck.o move.o mycrypt.o mymalloc.o \ - mysocket.o myrlimit.o myssl.o notify.o parse.o pcre.o player.o \ - plyrlist.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 \ +O_FILES=access.o atr_tab.o attrib.o boolexp.o bsd.o bufferq.o chunk.o \ + cmdlocal.o cmds.o command.o compress.o conf.o cque.o create.o \ + db.o destroy.o extchat.o extmail.o filecopy.o flaglocal.o \ + flags.o funcrypt.o function.o fundb.o funlist.o funlocal.o \ + funmath.o funmisc.o funstr.o funtime.o funufun.o game.o help.o \ + htab.o ident.o local.o lock.o log.o look.o malias.o markup.o \ + match.o memcheck.o move.o mycrypt.o mymalloc.o mysocket.o \ + myrlimit.o myssl.o notify.o parse.o pcre.o player.o plyrlist.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 # This is a dummy target, in case you type 'make' in the source @@ -64,28 +51,22 @@ netmud: $(O_FILES) @echo "Making netmud." -mv -f netmud netmud~ - $(CC) $(LDFLAGS) $(CCFLAGS) -o netmud $(O_FILES) $(LIBS) - -# By default, db.c initially allocates enough space for 5000 objects, then -# grows the space if needed. To change this value, include -# -DDB_INITIAL_SIZE=xxxx where xxxx is the new value (minimum 1). - + $(CC) $(CCFLAGS) -o netmud $(O_FILES) $(LDFLAGS) $(SQL_LDFLAGS) $(LIBS) # We recompile mysocket.c instead of reusing mysocket.o because we # want to do some error handing differently for info_slave. -info_slave: info_slave.c ident.o strdup.o sig.o wait.o mysocket.c \ - ../hdrs/lookup.h +info_slave: info_slave.c ident.o strdup.o sig.o wait.o mysocket.c ../hdrs/lookup.h @echo "Making info_slave." - $(CC) $(CCFLAGS) $(IDEFS) -c info_slave.c - $(CC) $(LDFLAGS) $(CCFLAGS) -DINFOSLAVE -o info_slave info_slave.o \ - ident.o strdup.o sig.o wait.o mysocket.c $(LIBS) + $(CC) $(CCFLAGS) -c info_slave.c + $(CC) $(CCFLAGS) -DINFOSLAVE -o info_slave info_slave.o \ + ident.o strdup.o sig.o wait.o mysocket.c $(LDFLAGS) $(LIBS) SSL_SLAVE_OBJS = strdup.o sig.o mymalloc.o mysocket.o myssl.o notify.o myrlimit.o strutil.o ident.o utils.o ssl_slave: ssl_slave.c $(SSL_SLAVE_OBJS) @echo "Making ssl_slave." - $(CC) $(CCFLAGS) $(IDEFS) -c ssl_slave.c - $(CC) $(LDFLAGS) $(CCFLAGS) -o ssl_slave ssl_slave.o \ - $(SSL_SLAVE_OBJS) $(LIBS) + $(CC) $(CCFLAGS) -c ssl_slave.c + $(CC) $(CCFLAGS) -o ssl_slave ssl_slave.o \ + $(SSL_SLAVE_OBJS) $(LDFLAGS) $(LIBS) # It should always be out of date. buildinf: @@ -93,9 +74,7 @@ @echo "/* This file generated automatically from Makefile */" >> ../hdrs/buildinf.h @echo "#define BUILDDATE \"`date`\"" >> ../hdrs/buildinf.h @echo "#define COMPILER \"$(CC)\"" >> ../hdrs/buildinf.h - @echo "#define CCFLAGS \"$(CCFLAGS)\"" >> ../hdrs/buildinf.h - @echo "#define RDEFS \"$(RDEFS)\"" >> ../hdrs/buildinf.h - @echo "#define IDEFS \"$(IDEFS)\"" >> ../hdrs/buildinf.h + @echo "#define CCFLAGS \"$(CFLAGS)\"" >> ../hdrs/buildinf.h # If funlocal.c doesn't exist, we want to build it from # funlocal.dst. @@ -141,12 +120,17 @@ ../hdrs/patches.h: if [ ! -f ../hdrs/patches.h ]; then \ - (cd ../utils; sh mkcmds.sh patches); \ + (cd ..; @PERL@ utils/mkcmds.pl patches); \ fi ../po/pennmush.pot: $(C_FILES) $(H_FILES) xgettext -d pennmush -kT -o ../po/pennmush.pot $(C_FILES) $(H_FILES) +htmltab.c: htmltab.gperf + gperf --output-file htmltab.c htmltab.gperf + +lmathtab.c: lmathtab.gperf + gperf --output-file lmathtab.c lmathtab.gperf etags: @ETAGS@ *.c ../hdrs/*.h @@ -163,28 +147,26 @@ indent: (set +e; for file in *.dst *.c ../hdrs/*.h ; do echo $$file; \ @INDENT@ -npro -kr -ci2 -ss -psl -ip4 -i2 -cs -l80 -lc75 -nut \ - -T accent_info -T acsflag -T aig_func -T ALIST -T ansi_string \ - -T atr_err -T ATRALIAS -T ATTR -T ATTRPAGE -T BOOL -T boolexp \ - -T boolexp_type -T BQUE -T branch_chain -T BUFFERQ \ - -T build_ansi_codes -T bvm_opcode -T BYTE -T CDESC -T CHAN \ - -T CHANLIST -T CHANUSER -T chunk_reference_t -T CNode -T COMLIST \ + -T acsflag -T aig_func -T ALIST -T ansi_string -T ATRALIAS -T ATTR \ + -T BOOL -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 HASHENT \ - -T HASHTAB -T heapframe -T help_file -T help_indx -T ident_t \ - -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 pcre_study_data \ - -T pcre_uint16 -T pcre_uint32 -T PE_Info -T PENNCONF \ - -T PENNCONFGROUP -T Port_t -T PRIV -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 sqlplatform -T StrNode \ - -T StrTree -T switch_mask -T SWITCH_VALUE -T tcheck -T tlist \ - -T ucp_type_table -T uschar -T UsedAttr -T USERFN_ENTRY \ - -T warn_type -T Word \ + -T HASHTAB -T heapframe -T IVAL -T list_type_list -T lock_list \ + -T lock_type -T LOCKMSGINFO -T LONG -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 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 recursion_info -T Region -T RegionHeader -T s_rec -T slab \ + -T sqlplatform -T StrNode -T StrTree -T switch_mask \ + -T SWITCH_VALUE -T tcheck -T tlist -T UIVAL -T uschar -T UsedAttr \ + -T USERFN_ENTRY -T WAIT_TYPE -T warn_type -T Word \ $$file ; done) clean: @@ -295,6 +277,7 @@ boolexp.o: ../hdrs/extchat.h boolexp.o: ../hdrs/bufferq.h boolexp.o: ../hdrs/strtree.h +boolexp.o: ../hdrs/mymalloc.h bsd.o: ../hdrs/copyrite.h bsd.o: ../config.h bsd.o: ../hdrs/conf.h @@ -411,7 +394,6 @@ cmds.o: ../hdrs/attrib.h cmds.o: ../hdrs/extmail.h cmds.o: ../hdrs/malias.h -cmds.o: ../hdrs/getpgsiz.h cmds.o: ../hdrs/parse.h cmds.o: ../hdrs/access.h cmds.o: ../hdrs/version.h @@ -440,7 +422,6 @@ command.o: ../hdrs/match.h command.o: ../hdrs/attrib.h command.o: ../hdrs/extmail.h -command.o: ../hdrs/getpgsiz.h command.o: ../hdrs/parse.h command.o: ../hdrs/access.h command.o: ../hdrs/version.h @@ -717,6 +698,7 @@ flags.o: ../hdrs/log.h flags.o: ../hdrs/dbio.h flags.o: ../hdrs/sort.h +flags.o: ../hdrs/mymalloc.h flags.o: ../hdrs/oldflags.h funcrypt.o: ../hdrs/copyrite.h funcrypt.o: ../config.h @@ -859,6 +841,7 @@ funmath.o: ../hdrs/pcre.h funmath.o: ../hdrs/sort.h funmath.o: ../hdrs/parse.h +funmath.o: lmathtab.c funmisc.o: ../hdrs/copyrite.h funmisc.o: ../config.h funmisc.o: ../hdrs/conf.h @@ -986,6 +969,7 @@ game.o: ../hdrs/function.h game.o: ../hdrs/help.h game.o: ../hdrs/dbio.h +game.o: ../hdrs/wait.h game.o: ../hdrs/ansi.h help.o: ../config.h help.o: ../hdrs/conf.h @@ -1179,6 +1163,7 @@ markup.o: ../hdrs/mymalloc.h markup.o: ../hdrs/log.h markup.o: ../hdrs/game.h +markup.o: htmltab.c match.o: ../hdrs/copyrite.h match.o: ../config.h match.o: ../hdrs/conf.h @@ -1248,7 +1233,22 @@ mycrypt.o: ../confmagic.h mymalloc.o: ../config.h mymalloc.o: ../options.h +mymalloc.o: ../hdrs/conf.h +mymalloc.o: ../hdrs/copyrite.h +mymalloc.o: ../hdrs/mushtype.h +mymalloc.o: ../hdrs/htab.h +mymalloc.o: ../hdrs/dbdefs.h +mymalloc.o: ../hdrs/mushdb.h +mymalloc.o: ../hdrs/flags.h +mymalloc.o: ../hdrs/ptab.h +mymalloc.o: ../hdrs/chunk.h +mymalloc.o: ../hdrs/log.h +mymalloc.o: ../hdrs/externs.h +mymalloc.o: ../hdrs/compile.h mymalloc.o: ../confmagic.h +mymalloc.o: ../hdrs/pcre.h +mymalloc.o: ../hdrs/getpgsiz.h +mymalloc.o: ../hdrs/mymalloc.h mysocket.o: ../hdrs/copyrite.h mysocket.o: ../config.h mysocket.o: ../hdrs/conf.h @@ -1402,6 +1402,7 @@ plyrlist.o: ../confmagic.h plyrlist.o: ../hdrs/pcre.h plyrlist.o: ../hdrs/attrib.h +plyrlist.o: ../hdrs/mymalloc.h predicat.o: ../hdrs/copyrite.h predicat.o: ../config.h predicat.o: ../hdrs/conf.h Index: src/myssl.c =================================================================== --- src/myssl.c (.../p3) (revision 1036) +++ src/myssl.c (.../p4) (revision 1036) @@ -74,6 +74,7 @@ #include #include #include +#include #include "conf.h" #include "mysocket.h" @@ -106,6 +107,8 @@ 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. */ @@ -114,6 +117,8 @@ { SSL_METHOD *meth; unsigned char context[128]; + DH *dh; + unsigned int reps = 1; if (!bio_err) { if (!SSL_library_init()) @@ -122,11 +127,25 @@ /* Error write context */ bio_err = BIO_new_fp(stderr, BIO_NOCLOSE); } -#ifndef HAS_DEV_URANDOM - /* We need to seed the RNG with RAND_seed() or RAND_egd() here. - * Where are we going to get an unpredictable seed? - */ -#endif + + do_rawlog(LT_ERR, "Seeding OpenSSL random number pool."); + while (!RAND_status()) { + /* At this point, a system with /dev/urandom or a EGD file in the usual + places will have enough entropy. Otherwise, be lazy and use random numbers + until it's satisfied. */ + uint32_t gibberish[4]; + int n; + + for (n = 0; n < 4; n++) + gibberish[n] = genrand_int32(); + + RAND_seed(gibberish, sizeof gibberish); + + reps += 1; + } + + do_rawlog(LT_ERR, "Seeded after %u %s.", reps, reps > 1 ? "cycles" : "cycle"); + /* Set up SIGPIPE handler here? */ @@ -169,7 +188,10 @@ SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); /* Set up DH callback */ - SSL_CTX_set_tmp_dh(ctx, get_dh1024()); + dh = get_dh1024(); + SSL_CTX_set_tmp_dh(ctx, dh); + /* The above function makes a private copy of this */ + DH_free(dh); /* Set the cipher list to the usual default list, except that * we'll allow anonymous diffie-hellman, too. @@ -234,16 +256,32 @@ }; DH *dh; if ((dh = DH_new()) == NULL) - return (NULL); + return NULL; + if (dh->p) { + BN_free(dh->p); + dh->p = NULL; + } + if (dh->g) { + BN_free(dh->g); + dh->g = NULL; + } + dh->p = BN_bin2bn(dh1024_p, sizeof(dh1024_p), NULL); + if (!dh->p) { + do_rawlog(LT_ERR, "Error in BN_bin2bn 1"); + DH_free(dh); + return NULL; + } + dh->g = BN_bin2bn(dh1024_g, sizeof(dh1024_g), NULL); - if ((dh->p == NULL) || (dh->g == NULL)) { + if (!dh->g) { + do_rawlog(LT_ERR, "ERror in BN_bin2bn 2"); DH_free(dh); - return (NULL); + return NULL; } - return (dh); -} + return dh; +} /** Associate an SSL object with a socket and return it. * \param sock socket descriptor to associate with an SSL object. Index: src/wiz.c =================================================================== --- src/wiz.c (.../p3) (revision 1036) +++ src/wiz.c (.../p4) (revision 1036) @@ -77,6 +77,7 @@ int start; /**< Limited results: start at this one. */ int count; /**< Limited results: return this many */ int end; /**< Limited results: return until this one.*/ + boolexp lock; /**< Boolexp to check against the objects. */ }; static int tport_dest_ok(dbref player, dbref victim, dbref dest); @@ -1728,65 +1729,6 @@ safe_integer(tot, buff, bp); } - -/** Reboot the game without disconnecting players. - * \verbatim - * This implements @shutdown/reboot, which performs a dump, saves - * information about which player is associated with which socket, - * and then re-execs the mush process without closing the sockets. - * \endverbatim - * \param player the enactor. - * \param flag if 0, normal dump; if 1, paranoid dump. - */ -void -do_reboot(dbref player, int flag) -{ - if (player == NOTHING) { - flag_broadcast(0, 0, - T - ("GAME: Reboot w/o disconnect from game account, please wait.")); - } else { - flag_broadcast(0, 0, - T - ("GAME: Reboot w/o disconnect by %s, please wait."), - Name(Owner(player))); - } - if (flag) { - globals.paranoid_dump = 1; - globals.paranoid_checkpt = db_top / 5; - if (globals.paranoid_checkpt < 1) - globals.paranoid_checkpt = 1; - } -#ifdef HAS_OPENSSL - close_ssl_connections(); -#endif - sql_shutdown(); - shutdown_queues(); - fork_and_dump(0); -#ifndef PROFILING -#ifndef WIN32 - /* Some broken libcs appear to retain the itimer across exec! - * So we make sure that if we get a SIGPROF in our next incarnation, - * we ignore it until our proper handler is set up. - */ - ignore_signal(SIGPROF); -#endif -#endif - dump_reboot_db(); -#ifdef INFO_SLAVE - kill_info_slave(); -#endif - local_shutdown(); - end_all_logs(); -#ifndef WIN32 - execl("netmush", "netmush", confname, NULL); -#else - execl("pennmush.exe", "pennmush.exe", "/run", NULL); -#endif /* WIN32 */ - exit(1); /* Shouldn't ever get here, but just in case... */ -} - - static int fill_search_spec(dbref player, const char *owner, int nargs, const char **args, struct search_spec *spec) @@ -1806,6 +1748,7 @@ spec->high = db_top - 1; spec->start = 1; /* 1-indexed */ spec->count = 0; + spec->lock = TRUE_BOOLEXP; is_wiz = Search_All(player) || See_All(player); /* set limits on who we search */ @@ -1956,6 +1899,8 @@ notify(player, T("Unknown zone.")); return -1; } + } else if (string_prefix("elock", class)) { + spec->lock = parse_boolexp(player, restriction, "Search"); } else if (string_prefix("eval", class)) { strcpy(spec->eval, restriction); } else if (string_prefix("ethings", class) || @@ -2023,6 +1968,8 @@ if (fill_search_spec(player, owner, nargs, args, &spec) < 0) { giveto(player, FIND_COST); + if (spec.lock != TRUE_BOOLEXP) + free_boolexp(spec.lock); return -1; } @@ -2033,6 +1980,8 @@ (ZMaster(spec.owner) && eval_lock(player, spec.owner, Zone_Lock)))) { giveto(player, FIND_COST); notify(player, T("You need a search warrant to do that.")); + if (spec.lock != TRUE_BOOLEXP) + free_boolexp(spec.lock); return -1; } @@ -2061,6 +2010,8 @@ if (*spec.powers && !flaglist_check_long("POWER", player, n, spec.powers, 1)) continue; + if (spec.lock != TRUE_BOOLEXP && !eval_boolexp(n, spec.lock, player)) + continue; if (*spec.eval) { char *ebuf1; const char *ebuf2; @@ -2099,5 +2050,7 @@ (*result)[nresults++] = (dbref) n; } + if (spec.lock != TRUE_BOOLEXP) + free_boolexp(spec.lock); return (int) nresults; } Index: src/htmltab.gperf =================================================================== --- src/htmltab.gperf (.../p3) (revision 0) +++ src/htmltab.gperf (.../p4) (revision 1036) @@ -0,0 +1,71 @@ +/* Gperf data file for creating the lookup function in markup.c to see + * if a given tag is an allowed HTML entity for Pueblo support. + */ + +%language=ANSI-C +%define hash-function-name htmltag_hash +%define lookup-function-name is_allowed_tag +%readonly-tables +%enum +%compare-lengths +%ignore-case +%% +A +B +I +U +STRONG +EM +ADDRESS +BLOCKQUOTE +CENTER +DEL +DIV +H1 +H2 +H3 +H4 +H5 +H6 +HR +INS +P +PRE +DIR +DL +DT +DD +LI +MENU +OL +UL +TABLE +CAPTION +COLGROUP +COL +THEAD +TFOOT +TBODY +TR +TD +TH +BR +FONT +IMG +SPAN +SUB +SUP +ABBR +ACRONYM +CITE +CODE +DFN +KBD +SAMP +VAR +BIG +S +SMALL +STRIKE +TT +%% Index: src/lmathtab.gperf =================================================================== --- src/lmathtab.gperf (.../p3) (revision 0) +++ src/lmathtab.gperf (.../p4) (revision 1036) @@ -0,0 +1,78 @@ +/* Gperf data file for lmath()-callable functions. */ +%language=ANSI-C +%define hash-function-name math_hash +%define lookup-function-name math_hash_lookup +%enum +%compare-lengths +%ignore-case +%struct-type +%define initializer-suffix ,NULL + +%{ +/** Declaration macro for math functions */ +#define MATH_FUNC(func) static void func(char **ptr, int nptr, char *buff, char **bp) + +/** Prototype macro for math functions */ +#define MATH_PROTO(func) static void func (char **ptr, int nptr, char *buff, char **bp) + +MATH_PROTO(math_add); +MATH_PROTO(math_sub); +MATH_PROTO(math_mul); +MATH_PROTO(math_div); +MATH_PROTO(math_floordiv); +MATH_PROTO(math_remainder); +MATH_PROTO(math_modulo); +MATH_PROTO(math_min); +MATH_PROTO(math_max); +MATH_PROTO(math_and); +MATH_PROTO(math_nand); +MATH_PROTO(math_or); +MATH_PROTO(math_nor); +MATH_PROTO(math_xor); +MATH_PROTO(math_band); +MATH_PROTO(math_bor); +MATH_PROTO(math_bxor); +MATH_PROTO(math_fdiv); +MATH_PROTO(math_mean); +MATH_PROTO(math_median); +MATH_PROTO(math_stddev); +MATH_PROTO(math_dist2d); +MATH_PROTO(math_dist3d); + +/** A math function. */ +%} +struct math { + const char *name; /**< Name of the function. */ + void (*func) (char **, int, char *, char **); /**< Pointer to function code. */ +}; +%% +ADD, math_add +SUB, math_sub +MUL, math_mul +DIV, math_div +FLOORDIV, math_floordiv +MOD, math_modulo +MODULO, math_modulo +MODULUS, math_modulo +REMAINDER, math_remainder +MIN, math_min +MAX, math_max +AND, math_and +NAND, math_nand +OR, math_or +NOR, math_nor +XOR, math_xor +BAND, math_band +BOR, math_bor +BXOR, math_bxor +FDIV, math_fdiv +MEAN, math_mean +MEDIAN, math_median +STDDEV, math_stddev +DIST2D, math_dist2d +DIST3D, math_dist3d +%% + +typedef struct math MATH; + + Index: src/services.c =================================================================== --- src/services.c (.../p3) (revision 1036) +++ src/services.c (.../p4) (revision 1036) @@ -1,12 +1,15 @@ -/* Win32 services routines */ - -/* Author: Nick Gammon */ +/** \file services.c + * \brief Win32 services routines + * + * Original author: Nick Gammon + */ -#ifdef WIN32 #include "copyrite.h" #include "config.h" +#ifdef WIN32 + #include /* for service and thread routines */ #include Index: src/attrib.c =================================================================== --- src/attrib.c (.../p3) (revision 1036) +++ src/attrib.c (.../p4) (revision 1036) @@ -49,22 +49,13 @@ /** How many attributes go in a "page" of attribute memory? */ #define ATTRS_PER_PAGE (200) -/** A page of memory for attributes. - * This structure is a collection of attribute memory. Rather than - * allocate new attributes one at a time, we allocate them in pages, - * and build a linked free list from the allocated page. - */ -typedef struct atrpage { - ATTR atrs[ATTRS_PER_PAGE]; /**< Array of attribute structures */ -} ATTRPAGE; +slab *attrib_slab = NULL; static int real_atr_clr(dbref thinking, char const *atr, dbref player, int we_are_wiping); -static ATTR *atr_free_list = NULL; -static ATTR *alloc_atr(void); -static ATTR *pop_free_list(void); -static void push_free_list(ATTR *); +static ATTR *alloc_atr(const void *hint); +static void free_atr(ATTR *); static void atr_free_one(ATTR *); static ATTR *find_atr_pos_in_list(ATTR ***pos, char const *name); static int can_create_attr(dbref player, dbref obj, char const *atr_name, @@ -201,7 +192,7 @@ * \return 0 on success, -1 on error */ int -string_to_atrflag(dbref player, char const *p, privbits * bits) +string_to_atrflag(dbref player, char const *p, privbits *bits) { privbits f; f = string_to_privs(attr_privs_set, p, 0); @@ -227,8 +218,8 @@ * \return 0 on success or -1 on error. */ int -string_to_atrflagsets(dbref player, char const *p, privbits * setbits, - privbits * clrbits) +string_to_atrflagsets(dbref player, char const *p, privbits *setbits, + privbits *clrbits) { int f; *setbits = *clrbits = 0; @@ -402,8 +393,8 @@ #define set_default_flags(atr,flags) \ do { \ ATTR *std = atr_match(AL_NAME((atr))); \ - if (std && !(flags) && !strcmp(AL_NAME(std), AL_NAME((atr)))) { \ - AL_FLAGS(atr) = AL_FLAGS(std); \ + if (std && !strcmp(AL_NAME(std), AL_NAME((atr)))) { \ + AL_FLAGS(atr) = AL_FLAGS(std) | flags; \ } else { \ AL_FLAGS(atr) = flags; \ } \ @@ -483,7 +474,7 @@ * \param atr_name the name for the attribute */ static ATTR * -create_atr(dbref thing, char const *atr_name) +create_atr(dbref thing, char const *atr_name, const ATTR *hint) { ATTR *ptr, **ins; char const *name; @@ -494,7 +485,7 @@ return NULL; /* allocate a new page, if needed */ - ptr = pop_free_list(); + ptr = alloc_atr(hint); if (ptr == NULL) { st_delete(name, &atr_names); return NULL; @@ -542,7 +533,7 @@ do_rawlog(LT_ERR, T("Bad attribute name %s on object %s"), atr, unparse_dbref(thing)); - ptr = create_atr(thing, atr); + ptr = create_atr(thing, atr, List(thing)); if (!ptr) return; @@ -554,7 +545,7 @@ if (!root) { do_rawlog(LT_ERR, T("Missing root attribute '%s' on object #%d!\n"), root_name, thing); - root = create_atr(thing, root_name); + root = create_atr(thing, root_name, ptr); set_default_flags(root, 0); AL_FLAGS(root) |= AF_ROOT; AL_CREATOR(root) = player; @@ -644,7 +635,7 @@ root = find_atr_in_list(ptr, missing_name); if (!root) { - root = create_atr(thing, missing_name); + root = create_atr(thing, missing_name, ptr); if (!root) return AE_TREE; @@ -670,7 +661,7 @@ *p = '`'; } - ptr = create_atr(thing, atr); + ptr = create_atr(thing, atr, root ? root : List(thing)); if (!ptr) return AE_ERROR; @@ -1165,7 +1156,7 @@ chunk_delete(ptr->data); st_delete(AL_NAME(ptr), &atr_names); - push_free_list(ptr); + free_atr(ptr); } } @@ -1977,54 +1968,30 @@ } -/** Return the head of the attribute free list. - * This function returns the head of the attribute free list. If there - * are no more ATTR's on the free list, allocate a new page. +/** Allocate a new ATTR from a slab allocator. * \return the pointer to the head of the attribute free list. */ static ATTR * -alloc_atr(void) +alloc_atr(const void *hint) { - if (!atr_free_list) { - ATTRPAGE *page; - int j; - page = (ATTRPAGE *) mush_malloc(sizeof(ATTRPAGE), "ATTRPAGE"); - if (!page) - mush_panic("Couldn't allocate memory in alloc_atr"); - for (j = 0; j < ATTRS_PER_PAGE - 1; j++) - AL_NEXT(page->atrs + j) = page->atrs + j + 1; - AL_NEXT(page->atrs + ATTRS_PER_PAGE - 1) = NULL; - atr_free_list = page->atrs; + if (!attrib_slab) { + attrib_slab = slab_create("attributes", sizeof(ATTR)); + slab_set_opt(attrib_slab, SLAB_ALLOC_BEST_FIT, 1); + slab_set_opt(attrib_slab, SLAB_HINTLESS_THRESHOLD, 10); } - return atr_free_list; -} -/** Pop an empty attribute off of the free list for use on - * an object. - * \return the pointer to an attribute, or NULL on error. - */ -static ATTR * -pop_free_list(void) -{ - ATTR *ptr; - ptr = alloc_atr(); - if (!ptr) - return NULL; - atr_free_list = AL_NEXT(ptr); - AL_NEXT(ptr) = NULL; - return ptr; + return slab_malloc(attrib_slab, hint); } -/** Push a now-unused attribute onto the free list + +/** Free an unused attribute struct. * \param An attribute that's been deleted from an object and * had its chunk reference deleted. */ static void -push_free_list(ATTR *a) +free_atr(ATTR *a) { - memset(a, 0, sizeof(*a)); - AL_NEXT(a) = atr_free_list; - atr_free_list = a; + slab_free(attrib_slab, a); } /** Delete one attribute, deallocating its name and data. @@ -2041,7 +2008,7 @@ st_delete(AL_NAME(a), &atr_names); if (a->data) chunk_delete(a->data); - push_free_list(a); + free_atr(a); } /** Return the compressed data for an attribute. Index: src/conf.c =================================================================== --- src/conf.c (.../p3) (revision 1036) +++ src/conf.c (.../p4) (revision 1036) @@ -611,7 +611,7 @@ *((int *) loc) = 0; else { if (from_cmd == 0) { - do_rawlog(LT_ERR, T("CONFIG: option %s value %s invalid.\n"), opt, val); + do_rawlog(LT_ERR, T("CONFIG: option %s value %s invalid."), opt, val); } return 0; } @@ -637,7 +637,7 @@ /* truncate if necessary */ if (len >= (size_t) maxval) { if (from_cmd == 0) { - do_rawlog(LT_ERR, T("CONFIG: option %s value truncated\n"), opt); + do_rawlog(LT_ERR, T("CONFIG: option %s value truncated"), opt); } len = maxval - 1; } @@ -675,7 +675,7 @@ if (n < NOTHING) { n = NOTHING; if (from_cmd == 0) { - do_rawlog(LT_ERR, T("CONFIG: option %s value limited to #%d\n"), opt, + do_rawlog(LT_ERR, T("CONFIG: option %s value limited to #%d"), opt, maxval); } } @@ -714,7 +714,7 @@ if ((maxval >= 0) && (n > maxval)) { n = maxval; if (from_cmd == 0) { - do_rawlog(LT_ERR, T("CONFIG: option %s value limited to %d\n"), opt, + do_rawlog(LT_ERR, T("CONFIG: option %s value limited to %d"), opt, maxval); } } @@ -778,7 +778,7 @@ if ((maxval >= 0) && (secs > maxval)) { secs = maxval; if (from_cmd == 0) { - do_rawlog(LT_ERR, T("CONFIG: option %s value limited to %d\n"), opt, + do_rawlog(LT_ERR, T("CONFIG: option %s value limited to %d"), opt, maxval); } } @@ -808,11 +808,11 @@ len = maxval - total - 1; if (len <= 0) { if (from_cmd == 0) - do_rawlog(LT_ERR, T("CONFIG: option %s value overflow\n"), opt); + do_rawlog(LT_ERR, T("CONFIG: option %s value overflow"), opt); return 0; } if (from_cmd == 0) - do_rawlog(LT_ERR, T("CONFIG: option %s value truncated\n"), opt); + do_rawlog(LT_ERR, T("CONFIG: option %s value truncated"), opt); } sprintf((char *) loc, "%s %s", (char *) loc, val); return 1; @@ -829,7 +829,7 @@ #define VALIDATE_ROOM(opt) do { \ if (!(GoodObject((opt)) && IsRoom((opt)))) { \ opt = 0; \ - do_rawlog(LT_ERR, T("CONFIG: option %s not a valid room!\n"), #opt); \ + do_rawlog(LT_ERR, T("CONFIG: option %s not a valid room!"), #opt); \ } \ } while (0) @@ -843,7 +843,7 @@ #define VALIDATE(opt) do { \ if (!GoodObject((opt)) && (opt) != NOTHING) { \ opt = 0; \ - do_rawlog(LT_ERR, T("CONFIG: option %s not a valid dbref or -1!\n"), \ + do_rawlog(LT_ERR, T("CONFIG: option %s not a valid dbref or -1!"), \ #opt); \ } \ } while (0) @@ -887,7 +887,7 @@ if (!restrict_command(val, p)) { if (source == 0) { do_rawlog(LT_ERR, - T("CONFIG: Invalid command or restriction for %s.\n"), val); + T("CONFIG: Invalid command or restriction for %s."), val); } return 0; } @@ -895,7 +895,7 @@ if (source == 0) { do_rawlog(LT_ERR, T - ("CONFIG: restrict_command %s requires a restriction value.\n"), + ("CONFIG: restrict_command %s requires a restriction value."), val); } return 0; @@ -910,8 +910,7 @@ if (!restrict_function(val, p)) { if (source == 0) { do_rawlog(LT_ERR, - T("CONFIG: Invalid function or restriction for %s.\n"), - val); + T("CONFIG: Invalid function or restriction for %s."), val); } return 0; } @@ -919,7 +918,7 @@ if (source == 0) { do_rawlog(LT_ERR, T - ("CONFIG: restrict_function %s requires a restriction value.\n"), + ("CONFIG: restrict_function %s requires a restriction value."), val); } return 0; @@ -938,14 +937,14 @@ *p++ = '\0'; if (!alias_command(val, p)) { if (source == 0) { - do_rawlog(LT_ERR, T("CONFIG: Couldn't alias %s to %s.\n"), p, val); + do_rawlog(LT_ERR, T("CONFIG: Couldn't alias %s to %s."), p, val); } return 0; } } else { if (source == 0) { do_rawlog(LT_ERR, - T("CONFIG: command_alias %s requires an alias.\n"), val); + T("CONFIG: command_alias %s requires an alias."), val); } return 0; } @@ -958,14 +957,14 @@ *p++ = '\0'; if (!alias_attribute(val, p)) { if (source == 0) { - do_rawlog(LT_ERR, T("CONFIG: Couldn't alias %s to %s.\n"), p, val); + do_rawlog(LT_ERR, T("CONFIG: Couldn't alias %s to %s."), p, val); } return 0; } } else { if (source == 0) { do_rawlog(LT_ERR, - T("CONFIG: attribute_alias %s requires an alias.\n"), val); + T("CONFIG: attribute_alias %s requires an alias."), val); } return 0; } @@ -978,14 +977,14 @@ *p++ = '\0'; if (!alias_function(val, p)) { if (source == 0) { - do_rawlog(LT_ERR, T("CONFIG: Couldn't alias %s to %s.\n"), p, val); + do_rawlog(LT_ERR, T("CONFIG: Couldn't alias %s to %s."), p, val); } return 0; } } else { if (source == 0) { do_rawlog(LT_ERR, - T("CONFIG: function_alias %s requires an alias.\n"), val); + T("CONFIG: function_alias %s requires an alias."), val); } return 0; } @@ -1002,7 +1001,7 @@ if (!val || !*val) { do_rawlog(LT_ERR, T - ("CONFIG: help_command requires a command name and file name.\n")); + ("CONFIG: help_command requires a command name and file name.")); return 0; } comm = val; @@ -1014,7 +1013,7 @@ } else { do_rawlog(LT_ERR, T - ("CONFIG: help_command requires a command name and file name.\n")); + ("CONFIG: help_command requires a command name and file name.")); return 0; } } else if (restrictions) { @@ -1049,7 +1048,7 @@ } if (source == 0) { - do_rawlog(LT_ERR, T("CONFIG: directive '%s' in cnf file ignored.\n"), opt); + do_rawlog(LT_ERR, T("CONFIG: directive '%s' in cnf file ignored."), opt); } return 0; } @@ -1229,7 +1228,9 @@ strcpy(options.ssl_ca_file, ""); options.ssl_require_client_cert = 0; #endif - options.mem_check = 0; + /* Set this to 1 so that allocations made before reading the config file + will be tracked. */ + options.mem_check = 1; strcpy(options.sql_platform, "disabled"); strcpy(options.sql_database, ""); strcpy(options.sql_username, ""); Index: src/db.c =================================================================== --- src/db.c (.../p3) (revision 1036) +++ src/db.c (.../p4) (revision 1036) @@ -222,11 +222,11 @@ o->zone = NOTHING; o->penn = 0; o->type = TYPE_GARBAGE; - o->flags = new_flag_bitmask("FLAG"); - o->powers = new_flag_bitmask("POWER"); o->warnings = 0; o->modification_time = o->creation_time = mudtime; o->attrcount = 0; + /* Flags are set by the functions that call this */ + o->powers = new_flag_bitmask("POWER"); if (current_state.garbage) current_state.garbage--; return newobj; @@ -1344,7 +1344,7 @@ /* make sure database is at least this big *1.5 */ case '~': db_init = (getref(f) * 3) / 2; - init_objdata_htab(db_init, NULL); + init_objdata_htab(db_init / 8, NULL); break; /* Use the MUSH 2.0 header stuff to see what's in this db */ case '+': @@ -1601,7 +1601,7 @@ break; case '~': db_init = (getref(f) * 3) / 2; - init_objdata_htab(db_init, NULL); + init_objdata_htab(db_init / 8, NULL); break; case '!': /* Read an object */ @@ -1801,6 +1801,8 @@ static void init_objdata_htab(int size, void (*free_data) (void *)) { + if (size < 128) + size = 128; hash_init(&htab_objdata, size, 4, free_data); hashinit(&htab_objdata_keys, 8, 32); } @@ -1810,7 +1812,9 @@ * that is built at database load and isn't saved to disk, but it * can be used for other purposes as well - it's a good general * tool for hackers who want to add their own data to objects. - * This function adds data to the hashtable. + * This function adds data to the hashtable. NULL data cleared + * that particular keybase/object entry. It does not free the + * data pointer. * \param thing dbref of object to associate the data with. * \param keybase base string for type of data. * \param data pointer to the data to store. @@ -1819,13 +1823,16 @@ void * set_objdata(dbref thing, const char *keybase, void *data) { - hashdelete(tprintf("%s_#%d", keybase, thing), &htab_objdata); + char keyname[BUFFER_LEN]; + + mush_strncpy(keyname, tprintf("%s_#%d", keybase, thing), BUFFER_LEN); + hashdelete(keyname, &htab_objdata); if (data) { - if (hashadd(tprintf("%s_#%d", keybase, thing), data, &htab_objdata) < 0) + if (hashadd(keyname, data, &htab_objdata) < 0) return NULL; if (hash_find(&htab_objdata_keys, keybase) == NULL) { - char *newkey = strdup(keybase); - hashadd(keybase, (void *) &newkey, &htab_objdata_keys); + char *newkey = mush_strdup(keyname, "objdata.key"); + hashadd(keybase, newkey, &htab_objdata_keys); } } return data; @@ -1869,7 +1876,7 @@ god = new_object(); /* #1 */ master_room = new_object(); /* #2 */ - init_objdata_htab(DB_INITIAL_SIZE, NULL); + init_objdata_htab(128, NULL); set_name(start_room, "Room Zero"); Type(start_room) = TYPE_ROOM; Index: src/function.c =================================================================== --- src/function.c (.../p3) (revision 1036) +++ src/function.c (.../p4) (revision 1036) @@ -38,6 +38,8 @@ 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. @@ -350,6 +352,8 @@ {"CMDS", fun_cmds, 1, 1, FN_REG}, {"COMP", fun_comp, 2, 3, FN_REG}, {"CON", fun_con, 1, 1, FN_REG}, + {"COND", fun_if, 2, INT_MAX, FN_NOPARSE}, + {"CONDALL", fun_if, 2, INT_MAX, FN_NOPARSE}, {"CONFIG", fun_config, 1, 1, FN_REG}, {"CONN", fun_conn, 1, 1, FN_REG}, {"CONTROLS", fun_controls, 2, 2, FN_REG}, @@ -361,8 +365,9 @@ {"CSECS", fun_csecs, 1, 1, FN_REG}, {"CTIME", fun_ctime, 1, 2, FN_REG}, {"DEC", fun_dec, 1, 1, FN_REG}, + {"DECODE64", fun_decode64, 1, -1, FN_REG}, {"DECOMPOSE", fun_decompose, 1, -1, FN_REG}, - {"DECRYPT", fun_decrypt, 2, 2, FN_REG}, + {"DECRYPT", fun_decrypt, 2, 3, FN_REG}, {"DEFAULT", fun_default, 2, INT_MAX, FN_NOPARSE}, {"DELETE", fun_delete, 3, 3, FN_REG}, {"DIE", fun_die, 2, 3, FN_REG}, @@ -379,7 +384,8 @@ {"ELIST", fun_itemize, 1, 5, FN_REG}, {"ELOCK", fun_elock, 2, 2, FN_REG}, {"EMIT", fun_emit, 1, -1, FN_REG}, - {"ENCRYPT", fun_encrypt, 2, 2, FN_REG}, + {"ENCODE64", fun_encode64, 1, -1, FN_REG}, + {"ENCRYPT", fun_encrypt, 2, 3, FN_REG}, {"ENTRANCES", fun_entrances, 0, 4, FN_REG}, {"ETIMEFMT", fun_etimefmt, 2, 2, FN_REG}, {"EQ", fun_eq, 2, 2, FN_REG}, @@ -402,7 +408,7 @@ {"FOLLOWING", fun_following, 1, 1, FN_REG}, {"FOREACH", fun_foreach, 2, 4, FN_REG}, {"FRACTION", fun_fraction, 1, 1, FN_REG}, - {"FUNCTIONS", fun_functions, 0, 0, FN_REG}, + {"FUNCTIONS", fun_functions, 0, 1, FN_REG}, {"FULLALIAS", fun_fullalias, 1, 1, FN_REG}, {"FULLNAME", fun_fullname, 1, 1, FN_REG}, {"GET", fun_get, 1, 1, FN_REG}, @@ -528,6 +534,8 @@ {"NATTRP", fun_nattr, 1, 1, FN_REG}, {"NCHILDREN", fun_lsearch, 1, 1, FN_REG}, {"NCON", fun_dbwalker, 1, 1, FN_REG}, + {"NCOND", fun_if, 2, INT_MAX, FN_NOPARSE}, + {"NCONDALL", fun_if, 2, INT_MAX, FN_NOPARSE}, {"NEXITS", fun_dbwalker, 1, 1, FN_REG}, {"NPLAYERS", fun_dbwalker, 1, 1, FN_REG}, {"NEARBY", fun_nearby, 2, 2, FN_REG}, @@ -644,6 +652,7 @@ {"SOUNDSLIKE", fun_soundlike, 2, 2, FN_REG}, {"SPACE", fun_space, 1, 1, FN_REG}, {"SPEAK", fun_speak, 2, 7, FN_REG}, + {"SPEAKPENN", fun_speak, 2, 7, FN_REG}, {"SPELLNUM", fun_spellnum, 1, 1, FN_REG}, {"SPLICE", fun_splice, 3, 4, FN_REG}, {"SQL", fun_sql, 1, 3, FN_REG}, @@ -770,41 +779,65 @@ do_list_functions(dbref player, int lc) { /* lists all built-in functions. */ - char *b = list_functions(); + char *b = list_functions(NULL); notify_format(player, "Functions: %s", lc ? strlower(b) : b); } /** Return a list of function names