From 47f5169c7f68d27158487e57902f75a5982e851b Mon Sep 17 00:00:00 2001 From: Rick L Bird Date: Sun, 17 Apr 2011 01:35:12 -0400 Subject: [PATCH] PennMUSH 1.8.2p8-1.8.3p7.patch This commit references the following PennMUSH enhancements: The following are refs in testing #37, #38, #39, #40, #42, #45, #47, #48, #51, #53, #54, #55, #56, #59, #61, #61 The following are resolved as well issue refs #36, #44, #52, #57, #60, and #67. This Patch also opens up an issue involving hash_flush ref #235 CHAT_SYSTEM is now disabled per ref #230 Old Configure system Removed and autoconf put in place. --- MANIFEST | 5 + Makefile.SH | 325 ----- Makefile.in | 219 +++ README.SQL | 141 +- U/Chk_MANI.U | 84 -- U/End.U | 28 - U/Findhdr.U | 124 -- U/Guess.U | 133 -- U/Head.U | 278 ---- U/Loc.U | 346 ----- U/MailList.U | 82 -- U/Myinit.U | 30 - U/Oldconfig.U | 623 --------- U/ccflags.U | 426 ------ U/cdecl.U | 48 - U/cf_name.U | 72 - U/d_argsinfp.U | 46 - U/d_assert.U | 41 - U/d_attribut.U | 64 - U/d_bindtextdomain.U | 41 - U/d_crypt.U | 87 -- U/d_force_ipv4.U | 21 - U/d_fpsetround.U | 93 -- U/d_gaistr.U | 27 - U/d_getadinf.U | 27 - U/d_getdate.U | 52 - U/d_gethbynm2.U | 27 - U/d_getnminf.U | 49 - U/d_getpagsz.U | 133 -- U/d_gettext.U | 41 - U/d_gnulibc.U | 70 - U/d_huge.U | 225 --- U/d_ieee.U | 55 - U/d_in2p.U | 27 - U/d_ipv6.U | 50 - U/d_keepsig.U | 78 -- U/d_lua.U | 113 -- U/d_memcpy.U | 63 - U/d_memmove.U | 0 U/d_newstyle.U | 41 - U/d_open3.U | 90 -- U/d_random.U | 53 - U/d_rlimit.U | 27 - U/d_round.U | 20 - U/d_sendmail.U | 32 - U/d_sigchld.U | 74 - U/d_signalproto.U | 78 -- U/d_signed_stdio.U | 56 - U/d_sigprocmask.U | 58 - U/d_snprintf.U | 39 - U/d_socklen.U | 38 - U/d_stdstdio.U | 30 - U/d_strchr.U | 109 -- U/d_strcoll.U | 40 - U/d_strxfrm.U | 40 - U/d_sysctl.U | 32 - U/d_tcl.U | 77 - U/d_textdomain.U | 41 - U/d_timelocal.U | 22 - U/d_toupper.U | 54 - U/d_uint32.U | 61 - U/d_uptime.U | 47 - U/d_urandom.U | 31 - U/d_uwait.U | 126 -- U/d_vsnprintf.U | 41 - U/i_arpanameser.U | 31 - U/i_errno.U | 46 - U/i_libintl.U | 33 - U/i_memory.U | 68 - U/i_netdb.U | 33 - U/i_nitcp.U | 34 - U/i_nl_types.U | 33 - U/i_setjmp.U | 31 - U/i_stdint.U | 32 - U/i_sysioctl.U | 202 --- U/i_syspage.U | 34 - U/i_sysvlimit.U | 34 - U/i_termio.U | 123 -- U/i_varhdr.U | 165 --- U/libc.U | 368 ----- U/libmysqlclient.U | 64 - U/libpth.U | 132 -- U/libs.U | 213 --- U/libssl.U | 62 - U/mailer.U | 65 - U/nametype.U | 136 -- U/sockopt.U | 120 -- U/usenm.U | 122 -- aclocal.m4 | 1320 +++++++++++++++++ config.guess | 1500 ++++++++++++++++++++ configure.ac | 347 +++++ game/README | 81 +- game/data/README | 1 - game/log/README | 21 + game/mushcnf.dst | 13 +- game/txt/Makefile | 2 - game/txt/changes/0.80 | 8 +- game/txt/compose.sh.SH | 82 -- game/txt/hlp/cobra_chat.hlp | 158 ++- game/txt/hlp/cobra_conf.hlp | 2 + hdrs/access.h | 47 +- hdrs/ansi.h | 188 ++- hdrs/atr_tab.h | 9 +- hdrs/attrib.h | 8 +- hdrs/bufferq.h | 24 +- hdrs/case.h | 2 +- hdrs/chunk.h | 23 +- hdrs/command.h | 30 +- hdrs/compile.h | 22 +- hdrs/conf.h | 14 +- hdrs/csrimalloc.h | 2 + hdrs/dbdefs.h | 12 +- hdrs/dbio.h | 21 +- hdrs/extchat.h | 85 +- hdrs/externs.h | 300 ++-- hdrs/extmail.h | 37 +- hdrs/flags.h | 40 +- hdrs/function.h | 44 +- hdrs/game.h | 8 +- hdrs/getpgsiz.h | 40 +- hdrs/htab.h | 69 +- hdrs/ident.h | 2 +- hdrs/intmap.h | 28 + hdrs/lock.h | 89 +- hdrs/lookup.h | 60 + hdrs/modules.h | 5 +- hdrs/mushdb.h | 12 +- hdrs/mushtype.h | 31 +- hdrs/mymalloc.h | 29 + hdrs/mypcre.h | 215 +++ hdrs/mysocket.h | 19 +- hdrs/parse.h | 47 +- hdrs/pcre.h | 203 --- hdrs/privtab.h | 20 +- hdrs/ptab.h | 9 +- hdrs/pueblo.h | 23 - hdrs/shs.h | 4 +- hdrs/sort.h | 30 + hdrs/strtree.h | 2 + hdrs/wait.h | 42 + hints/README | 16 + hints/cygwin.txt | 1 + hints/darwin-fink.sh | 7 - hints/darwin.sh | 3 - hints/freebsd.sh | 6 - hints/freebsd.txt | 8 + hints/linux.txt | 6 + hints/linux_2.sh | 14 - hints/mac_os_x.txt | 36 + hints/mingw32.sh | 4 - hints/mingw32.txt | 1 + hints/netbsd.txt | 17 + hints/next.sh | 5 - hints/openbsd.sh | 4 - hints/openbsd.txt | 8 + hints/os2.sh | 6 - hints/ultrix.sh | 1 - hints/win32-gcc.sh | 7 - hints/windows.txt | 6 + install-sh | 401 ++++++ src/{Makefile.SH => Makefile.in} | 1068 ++++++-------- src/SWITCHES | 1 + src/access.c | 230 +-- src/atr_tab.c | 24 +- src/attrib.c | 222 +-- src/boolexp.c | 99 +- src/bsd.c | 1754 +++++++++++------------ src/bufferq.c | 57 +- src/chunk.c | 256 ++-- src/cmds.c | 251 +++- src/command.c | 351 +++-- src/comp_h.c | 21 +- src/comp_w.c | 15 +- src/comp_w8.c | 14 +- src/compress.c | 2 +- src/conf.c | 181 ++- src/cque.c | 892 +++++++----- src/create.c | 7 +- src/cron.c | 10 +- src/csrimalloc.c | 317 +++-- src/db.c | 193 ++- src/destroy.c | 11 +- src/division.c | 16 +- src/extchat.c | 1058 ++++++-------- src/extmail.c | 186 +-- src/flags.c | 88 +- src/funcrypt.c | 206 ++- src/function.c | 350 +++-- src/fundb.c | 146 +- src/funlist.c | 1119 ++++++--------- src/funmath.c | 692 +++++---- src/funmisc.c | 142 +- src/funstr.c | 1071 +++++++------- src/funtime.c | 92 +- src/funufun.c | 45 +- src/game.c | 234 ++-- src/help.c | 154 +- src/htab.c | 839 ++++++----- src/htmltab.c | 256 ++++ src/htmltab.gperf | 71 + src/ident.c | 286 ++-- src/info_master.c | 395 ++++++ src/info_slave.c | 649 +++++++-- src/intmap.c | 479 +++++++ src/lmathtab.c | 276 ++++ src/lmathtab.gperf | 78 ++ src/lock.c | 236 ++-- src/log.c | 34 +- src/look.c | 428 ++---- src/malias.c | 33 +- src/markup.c | 2252 ++++++++++++++++++++++++++++++ src/match.c | 15 +- src/memcheck.c | 52 +- src/modules.c | 2 + src/move.c | 10 +- src/mushlua.i | 6 + src/mymalloc.c | 602 +++++++- src/myrlimit.c | 141 ++ src/mysocket.c | 254 ++-- src/myssl.c | 43 +- src/notify.c | 349 ++--- src/parse.c | 448 ++++-- src/pcre.c | 144 +- src/player.c | 24 +- src/plyrlist.c | 24 +- src/portmsg.c | 72 +- src/predicat.c | 11 +- src/privtab.c | 45 +- src/prog.c | 6 - src/ptab.c | 161 ++- src/rob.c | 7 +- src/services.c | 8 +- src/set.c | 133 +- src/shs.c | 6 +- src/sig.c | 30 +- src/sort.c | 711 ++++++++++ src/speech.c | 189 ++- src/sql.c | 1305 +++++++++++------ src/strdup.c | 2 +- src/strtree.c | 31 +- src/strutil.c | 838 +++-------- src/tables.c | 64 +- src/timer.c | 13 +- src/unparse.c | 22 +- src/utils.c | 197 ++- src/version.c | 9 +- src/wait.c | 190 +++ src/warnings.c | 6 +- src/wild.c | 170 ++- src/wiz.c | 142 +- test/MUSHConnection.pm | 158 +++ test/PennMUSH.pm | 113 ++ test/README | 22 + test/TestHarness.pm | 170 +++ test/alltests.sh | 4 + test/alltests.sh.in | 4 + test/runtest.pl | 26 + test/testalias.pl | 13 + test/testatree.pl | 251 ++++ test/testdecompose.pl | 7 + test/testdigest.pl | 13 + test/testdistxd.pl | 10 + test/testfirstof.pl | 13 + test/testgrep.pl | 37 + test/testhastype.pl | 12 + test/testinsert.pl | 21 + test/testjust.pl | 20 + test/testletq.pl | 3 + test/testmath.pl | 53 + test/testnull.pl | 9 + test/testpage.pl | 2 + test/testrand.pl | 10 + test/testreswitch.pl | 20 + test/testsetfuns.pl | 7 + test/teststringsecs.pl | 12 + test/testtr.pl | 8 + test/testtrim.pl | 18 + utils/fixdepend.pl | 7 +- utils/gentables.c | 50 +- utils/mkcmds.pl | 254 ++++ win32/README.mingw | 19 +- win32/confmagic.h | 118 +- win32/patches.h | 2 +- 283 files changed, 22258 insertions(+), 17516 deletions(-) delete mode 100644 Makefile.SH create mode 100644 Makefile.in delete mode 100644 U/Chk_MANI.U delete mode 100644 U/End.U delete mode 100644 U/Findhdr.U delete mode 100644 U/Guess.U delete mode 100644 U/Head.U delete mode 100644 U/Loc.U delete mode 100644 U/MailList.U delete mode 100644 U/Myinit.U delete mode 100644 U/Oldconfig.U delete mode 100644 U/ccflags.U delete mode 100644 U/cdecl.U delete mode 100644 U/cf_name.U delete mode 100644 U/d_argsinfp.U delete mode 100644 U/d_assert.U delete mode 100644 U/d_attribut.U delete mode 100644 U/d_bindtextdomain.U delete mode 100644 U/d_crypt.U delete mode 100644 U/d_force_ipv4.U delete mode 100644 U/d_fpsetround.U delete mode 100644 U/d_gaistr.U delete mode 100644 U/d_getadinf.U delete mode 100644 U/d_getdate.U delete mode 100644 U/d_gethbynm2.U delete mode 100644 U/d_getnminf.U delete mode 100644 U/d_getpagsz.U delete mode 100644 U/d_gettext.U delete mode 100644 U/d_gnulibc.U delete mode 100644 U/d_huge.U delete mode 100644 U/d_ieee.U delete mode 100644 U/d_in2p.U delete mode 100644 U/d_ipv6.U delete mode 100644 U/d_keepsig.U delete mode 100644 U/d_lua.U delete mode 100644 U/d_memcpy.U delete mode 100644 U/d_memmove.U delete mode 100644 U/d_newstyle.U delete mode 100644 U/d_open3.U delete mode 100644 U/d_random.U delete mode 100644 U/d_rlimit.U delete mode 100644 U/d_round.U delete mode 100644 U/d_sendmail.U delete mode 100644 U/d_sigchld.U delete mode 100644 U/d_signalproto.U delete mode 100644 U/d_signed_stdio.U delete mode 100644 U/d_sigprocmask.U delete mode 100644 U/d_snprintf.U delete mode 100644 U/d_socklen.U delete mode 100644 U/d_stdstdio.U delete mode 100644 U/d_strchr.U delete mode 100644 U/d_strcoll.U delete mode 100644 U/d_strxfrm.U delete mode 100644 U/d_sysctl.U delete mode 100644 U/d_tcl.U delete mode 100644 U/d_textdomain.U delete mode 100644 U/d_timelocal.U delete mode 100644 U/d_toupper.U delete mode 100644 U/d_uint32.U delete mode 100644 U/d_uptime.U delete mode 100644 U/d_urandom.U delete mode 100644 U/d_uwait.U delete mode 100644 U/d_vsnprintf.U delete mode 100644 U/i_arpanameser.U delete mode 100644 U/i_errno.U delete mode 100644 U/i_libintl.U delete mode 100644 U/i_memory.U delete mode 100644 U/i_netdb.U delete mode 100644 U/i_nitcp.U delete mode 100644 U/i_nl_types.U delete mode 100644 U/i_setjmp.U delete mode 100644 U/i_stdint.U delete mode 100644 U/i_sysioctl.U delete mode 100644 U/i_syspage.U delete mode 100644 U/i_sysvlimit.U delete mode 100644 U/i_termio.U delete mode 100644 U/i_varhdr.U delete mode 100644 U/libc.U delete mode 100644 U/libmysqlclient.U delete mode 100644 U/libpth.U delete mode 100644 U/libs.U delete mode 100644 U/libssl.U delete mode 100644 U/mailer.U delete mode 100644 U/nametype.U delete mode 100644 U/sockopt.U delete mode 100644 U/usenm.U create mode 100644 aclocal.m4 create mode 100644 config.guess create mode 100644 configure.ac delete mode 100644 game/data/README create mode 100644 hdrs/intmap.h create mode 100644 hdrs/lookup.h create mode 100644 hdrs/mypcre.h create mode 100644 hdrs/sort.h create mode 100644 hdrs/wait.h create mode 100644 hints/README create mode 100644 hints/cygwin.txt delete mode 100644 hints/darwin-fink.sh delete mode 100644 hints/darwin.sh delete mode 100644 hints/freebsd.sh create mode 100644 hints/freebsd.txt create mode 100644 hints/linux.txt delete mode 100644 hints/linux_2.sh create mode 100644 hints/mac_os_x.txt delete mode 100644 hints/mingw32.sh create mode 100644 hints/mingw32.txt create mode 100644 hints/netbsd.txt delete mode 100644 hints/next.sh delete mode 100644 hints/openbsd.sh create mode 100644 hints/openbsd.txt delete mode 100644 hints/os2.sh delete mode 100644 hints/ultrix.sh delete mode 100644 hints/win32-gcc.sh create mode 100644 hints/windows.txt create mode 100644 install-sh rename src/{Makefile.SH => Makefile.in} (66%) create mode 100644 src/htmltab.c create mode 100644 src/htmltab.gperf create mode 100644 src/info_master.c create mode 100644 src/intmap.c create mode 100644 src/lmathtab.c create mode 100644 src/lmathtab.gperf create mode 100644 src/markup.c create mode 100644 src/myrlimit.c create mode 100644 src/sort.c create mode 100644 src/wait.c create mode 100644 test/MUSHConnection.pm create mode 100644 test/PennMUSH.pm create mode 100644 test/README create mode 100644 test/TestHarness.pm create mode 100755 test/alltests.sh create mode 100644 test/alltests.sh.in create mode 100644 test/runtest.pl create mode 100644 test/testalias.pl create mode 100644 test/testatree.pl create mode 100644 test/testdecompose.pl create mode 100644 test/testdigest.pl create mode 100644 test/testdistxd.pl create mode 100644 test/testfirstof.pl create mode 100644 test/testgrep.pl create mode 100644 test/testhastype.pl create mode 100644 test/testinsert.pl create mode 100644 test/testjust.pl create mode 100644 test/testletq.pl create mode 100644 test/testmath.pl create mode 100644 test/testnull.pl create mode 100644 test/testpage.pl create mode 100644 test/testrand.pl create mode 100644 test/testreswitch.pl create mode 100644 test/testsetfuns.pl create mode 100644 test/teststringsecs.pl create mode 100644 test/testtr.pl create mode 100644 test/testtrim.pl diff --git a/MANIFEST b/MANIFEST index 61dda92..4e9cc61 100644 --- a/MANIFEST +++ b/MANIFEST @@ -79,9 +79,11 @@ hdrs/getpgsiz.h hdrs/help.h hdrs/htab.h hdrs/ident.h +hdrs/intmap.h hdrs/intrface.h hdrs/lock.h hdrs/log.h +hdrs/lookup.h hdrs/malias.h hdrs/match.h hdrs/mushdb.h @@ -158,6 +160,8 @@ src/fundb.c src/fundiv.c src/funlist.c src/funmath.c +src/lmathtab.c +src/lmathtab.gperf src/funmisc.c src/funstr.c src/funtime.c @@ -193,6 +197,7 @@ src/services.c src/set.c src/shs.c src/sig.c +src/sort.c src/speech.c src/sql.c src/strdup.c diff --git a/Makefile.SH b/Makefile.SH deleted file mode 100644 index 8a42ac7..0000000 --- a/Makefile.SH +++ /dev/null @@ -1,325 +0,0 @@ -case $CONFIG in -'') - if test -f config.sh; then TOP=.; - elif test -f ../config.sh; then TOP=..; - elif test -f ../../config.sh; then TOP=../..; - elif test -f ../../../config.sh; then TOP=../../..; - elif test -f ../../../../config.sh; then TOP=../../../..; - else - echo "Can't find config.sh."; exit 1 - fi - . $TOP/config.sh - ;; -esac -: This forces SH files to create target in same directory as SH file. -: This is so that make depend always knows where to find SH derivatives. -case "$0" in -*/*) cd `expr X$0 : 'X\(.*\)/'` ;; -esac - -echo "Extracting Makefile (with variable substitutions)" - -if test "x$OSTYPE" = "xmsys"; then - INSTALL_LINKS="$lns ../src/netmud.exe netmush" -else - INSTALL_LINKS="$lns ../src/netmud netmush; \ - $lns ../src/console console; \ - $lns ../src/info_slave info_slave" -fi - -: This section of the file will have variable substitutions done on it. -: Move anything that needs config subs from !NO!SUBS! section to !GROK!THIS!. -: Protect any dollar signs and backticks that you do not want interpreted -: by putting a backslash in front. You may delete these comments. -$spitshell >Makefile <>Makefile <<'!NO!SUBS!' - - -# stupid SYS V shell -SHELL=/bin/sh -# Where to install with 'make globalinstall' -GLOBAL_INSTALL=/usr/libexec/cobramush - -# Where to install with 'make debianinstall' -DEB_INSTALL=$(DESTDIR)/usr/lib/cobramush/game -DEB_BIN=$(DESTDIR)/usr/games - -all: config.h options.h autogen game/mush.cnf - @echo "Making all in src." - (cd src; make all "CC=$(CC)" "CCFLAGS=$(CCFLAGS)" \ - "LDFLAGS=$(LDFLAGS)" "CLIBS=$(CLIBS)" "MAKE=$(MAKE)" \ - "MAKEFLAGS=$(MAKEFLAGS)") - @echo "If the make was successful, use 'make install' to install links." - -config.h: Configure - @echo "Looks like your Configure has been updated." - @echo "Run that first." - exit 1 - -options.h: options.h.dist - @echo "Please use 'make update' to update your options.h file from options.h.dist" - @echo "You must cp options.h.dist to options.h and edit it." - exit 1 - -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 - (perl utils/mkcmds.pl commands) - -hdrs/switches.h: src/SWITCHES Patchlevel - (perl utils/mkcmds.pl switches) - -src/switchinc.c: src/SWITCHES Patchlevel - (perl utils/mkcmds.pl switches) - -hdrs/funs.h: src/fun*.c src/bsd.c src/conf.c src/cque.c src/extmail.c src/help.c src/wiz.c src/sql.c Patchlevel - (perl utils/mkcmds.pl functions) - -install: localized all game/restart - -rm -f game/netmush - -rm -f game/console - -rm -f game/info_slave - (cd game; $(INSTALL_LINKS)) - (cd game/txt; make) - @echo "If you plan to run multiple MUSHes, consider running 'make customize'" - -netmud: - (cd src; make netmud "CC=$(CC)" "CCFLAGS=$(CCFLAGS)" \ - "LDFLAGS=$(LDFLAGS)" "CLIBS=$(CLIBS)" ) - -console: - (cd src; make console "CC=$(CC)" "CCFLAGS=$(CCFLAGS)" \ - "LDFLAGS=$(LDFLAGS)" "CLIBS=$(CLIBS)" ) - -access: - utils/make_access_cnf.sh game - -cobramush.pot: - (cd src; make ../po/cobramush.pot) - -localized: - -echo "Localizing for your locale..." - -(cd po; make localized) - -portmsg: - (cd src; make portmsg "CC=$(CC)" "CCFLAGS=$(CCFLAGS)" \ - "LDFLAGS=$(LDFLAGS)" "CLIBS=$(CLIBS)" ) - -announce: - (cd src; make announce "CC=$(CC)" "CCFLAGS=$(CCFLAGS)" \ - "LDFLAGS=$(LDFLAGS)" "CLIBS=$(CLIBS)" ) - -versions: game/txt/changes/* - -@rm -rf game/txt/changes.txt - (cd game/txt && ruby genchanges.rb) - -safety: - $(CP) src/*.c /var/cobramush-bak/src - $(CP) hdrs/*.h /var/cobramush-bak/hdrs - $(CP) * /var/cobramush-bak - -distdepend: hdrs/funs.h hdrs/cmds.h - (cd src; make depend "CC=$(CC)" "CCFLAGS=$(CCFLAGS)" \ - "LDFLAGS=$(LDFLAGS)" "CLIBS=$(CLIBS)" ) - -# REQUIRES GNU INDENT! DON'T INDENT WITH ANYTHING ELSE! -indent: -# @(cd src; make indent) - -protoize: - (cd src; make protoize "CCFLAGS=$(CCFLAGS)") - -!NO!SUBS! - -: This section of the file will have variable substitutions done on it. -: Move anything that needs config subs from !NO!SUBS! section to !GROK!THIS!. -: Protect any dollar signs and backticks that you do not want interpreted -: by putting a backslash in front. You may delete these comments. -$spitshell >>Makefile <>Makefile <<'!NO!SUBS!' - -clean: - (cd src; make clean) - (cd game; rm -f netmush console info_slave) - -distclean: - (cd hdrs; rm -f *.orig *~ \#* *.rej *.bak funs.h cmds.h buildinf.h patches.h) - (cd utils; rm -f *.orig *~ \#* *.rej *.bak mkcmds.sh) - (cd game; rm -rf *.log netmush info_slave *.orig *.rej *~ *.bak mush.cnf) - (cd os2; rm -rf *.rej *.orig *~ *.bak) - (cd src; make distclean; rm -f Makefile) - (cd game/txt; make clean) - (rm -rf .config Makefile config.h config.sh options.h) - -totallyclean: distclean - (cd hdrs; rm -rf *.rej) - (cd src; rm -rf *.rej) - -rm -f Makefile - -distci: distclean ci-src ci-game - -ci-src: - -(yes . | ci -l -f -N$(NAME) FAQ* BUGS COPY* CHANGE* READ* MANIFEST \ - Configure utils/* Makefile.SH Patchlevel config_h.SH confmagic.h \ - *.dist src/Makefile src/SWITCHES src/*.c src/*.dst \ - hdrs/* hints/* os2/*) - -ci-game: - -(yes . | ci -l -f -N$(NAME) game/restart game/mushcnf.dst \ - game/access.README \ - game/txt/* game/txt/nws/* game/txt/evt/* game/txt/hlp/* ) - -diffs: - @make indent > /dev/null 2>&1 - @make versions > /dev/null 2>&1 - @make touchswitches > /dev/null 2>&1 - @make autogen > /dev/null 2>&1 - @(prcs diff -r$(VS) -N cobramush `cat MANIFEST` | grep -v 'Index:') - -checkin: versions autogen - @prcs checkin - -commit: indent - @svn commit - -patch: versions - @make-patch-header - @make diffs - -etags: - (cd src; make etags) - -ctags: - (cd src; make ctags) - -dist.tar.Z: distclean dist.tar - compress /tmp/dist.tar - -dist.tar.gz: distclean dist.tar - gzip /tmp/dist.tar - -touchswitches: - @touch src/SWITCHES - -dist.tar: indent distclean versions touchswitches autogen - makedist -c cobramush - tar -cvf /tmp/dist.tar cobramush -# CobraMUSH does not pgp sign distributions at this moment -# -pgp -sb /tmp/dist.tar - -rm -rf cobramush - -globalinstall: install - (cd game/txt; make clean compose.sh) - $(INSTALLDIR) $(GLOBAL_INSTALL) - $(CP) -R game/* $(GLOBAL_INSTALL) - rm -f $(GLOBAL_INSTALL)/netmush $(GLOBAL_INSTALL)/info_slave - rm -f $(GLOBAL_INSTALL)/console - $(INSTALL) config.sh $(GLOBAL_INSTALL)/config.sh - $(INSTALL) src/netmud $(GLOBAL_INSTALL)/netmush - $(INSTALL) src/console $(GLOBAL_INSTALL)/console - $(INSTALL) src/info_slave utils/ln-dir.sh $(GLOBAL_INSTALL) - $(CHMOD) a+rX -R $(GLOBAL_INSTALL) - @echo "** Files installed in $(GLOBAL_INSTALL). Feel free to move them." - @echo "** You can run $(GLOBAL_INSTALL)/ln-dir.sh to create a user directory," - @echo "** or symlink that to somewhere easier to run. You may wish to strip them." - -debianinstall: install - (cd game/txt; make clean compose.sh) - $(INSTALLDIR) $(DEB_INSTALL) - $(INSTALLDIR) $(DEB_BIN) - $(CP) -R game/* $(DEB_INSTALL) - -rm -f $(DEB_INSTALL)/netmush $(DEB_INSTALL)/info_slave - -rm -f $(DEB_INSTALL)/console - $(INSTALL) config.sh $(DEB_INSTALL)/config.sh - $(INSTALL) src/netmud $(DEB_INSTALL)/netmush - $(INSTALL) src/console $(DEB_INSTALL)/console - $(INSTALL) src/info_slave $(DEB_INSTALL)/info_slave - $(INSTALL) utils/cobramush-install $(DEB_BIN)/cobramush-install - $(CHMOD) a+rX -R $(DEB_INSTALL) - $(CHMOD) a+rX $(DEB_BIN)/cobramush-install - @echo "** Files installed in $(DEB_INSTALL)." - @echo "** You can run cobramush-install to create a user directory." - -!NO!SUBS! -chmod 644 Makefile diff --git a/Makefile.in b/Makefile.in new file mode 100644 index 0000000..3a9f8c8 --- /dev/null +++ b/Makefile.in @@ -0,0 +1,219 @@ +# Makefile for CobraMUSH + +# - System configuration - # + +VERSION=0.80 +PATCHLEVEL=0 + +# +# This section of the file should be automatically configured by +# the Configure script. If it doesn't work, you might try starting +# from the Makefile.old that's included instead, and reporting +# your problem (including this Makefile) to pennmush-bugs@pennmush.org +# +# If you want to profile the code, add -pg -a -DPROFILING to CCFLAGS +# and (probably) remove -O +# +MAKE=@MAKE@ +CC=@CC@ + +SQL_CFLAGS=@MYSQL_CFLAGS@ @POSTGRESQL_CFLAGS@ @SQLITE3_CFLAGS@ +SQL_LDFLAGS=@MYSQL_LDFLAGS@ @POSTGRESQL_LDFLAGS@ @SQLITE3_LDFLAGS@ + +CCFLAGS=@CFLAGS@ -I.. -I../hdrs -I/usr/include/lua5.1 @CPPFLAGS@ @PCRE_CFLAGS@ +LDFLAGS=@LDFLAGS@ +CLIBS=@LIBS@ @PCRE_LIBS@ -llua5.1 -lltdl +INSTALL=@INSTALL@ +INSTALLDIR=$installdir +CP=@CP@ +CHMOD=@CHMOD@ +INSTALL_LINKS=@LN_S@ ../src/netmud netmush; @LN_S@ ../src/info_slave info_slave + +# stupid SYS V shell +SHELL=/bin/sh +# Where to install with 'make globalinstall' +GLOBAL_INSTALL=@libexecdir@ + +all: config.h options.h autogen game/mush.cnf + @echo "Making all in src." + (cd src; @MAKE@ all "CC=$(CC)" "CCFLAGS=$(CCFLAGS)" \ + "LDFLAGS=$(LDFLAGS)" "CLIBS=$(CLIBS)" "MAKE=$(MAKE)" \ + "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 + @echo "Looks like your configure has been updated." + @echo "Run that first. If you did just run configure and" + @echo "it said that config.h was unchanged, 'touch config.h'" + @echo "to suppress this message and continue compiling." + @exit 1 + +options.h: options.h.dist + @echo "Please use 'make update' to update your options.h file from options.h.dist" + @echo "You must cp options.h.dist to options.h and edit it." + @exit 1 + +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 + @PERL@ utils/mkcmds.pl commands + +hdrs/switches.h: src/SWITCHES Patchlevel + @PERL@ utils/mkcmds.pl switches + +src/switchinc.c: src/SWITCHES Patchlevel + @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 + @PERL@ utils/mkcmds.pl functions + +hdrs/patches.h: patches/* + @PERL@ utils/mkcmds.pl patches + +install: localized all + -rm -f game/netmush + -rm -f game/info_slave + (cd game; $(INSTALL_LINKS)) + (cd game/txt; make) + @echo "If you plan to run multiple MUSHes, consider running 'make customize'" + +netmud: + (cd src; make netmud "CC=$(CC)" "CCFLAGS=$(CCFLAGS)" \ + "SQL_CFLAGS=$(SQL_CFLAGS)" "SQL_LDFLAGS=$(SQL_LDFLAGS)" \ + "LDFLAGS=$(LDFLAGS)" "CLIBS=$(CLIBS)" ) + +access: + utils/make_access_cnf.sh game + +pennmush.pot: + (cd src; make ../po/pennmush.pot) + +localized: + -echo "Localizing for your locale..." + -(cd po; make localized) + +portmsg: + (cd src; make portmsg "CC=$(CC)" "CCFLAGS=$(CCFLAGS)" \ + "LDFLAGS=$(LDFLAGS)" "CLIBS=$(CLIBS)" ) + +ssl_slave: + (cd src; make ssl_slave "CC=$(CC)" "CCFLAGS=$(CCFLAGS)" \ + "LDFLAGS=$(LDFLAGS)" "CLIBS=$(CLIBS)" "MAKE=$(MAKE)" \ + "MAKEFLAGS=$(MAKEFLAGS)") + +versions: CHANGES* + -@rm -rf CHANGES*~ CHANGES*bak + @utils/mkvershlp.pl game/txt/hlp CHANGES* + +safety: + $(CP) src/*.c + $(CP) hdrs/*.h + $(CP) * + +distdepend: hdrs/funs.h hdrs/cmds.h + (cd src; @MAKE@ depend "CC=$(CC)" "CCFLAGS=$(CCFLAGS)" \ + "LDFLAGS=$(LDFLAGS)" "CLIBS=$(CLIBS)" ) + +# REQUIRES GNU INDENT! DON'T INDENT WITH ANYTHING ELSE! +indent: + @(cd src; make indent) + +customize: update-conf + -@@PERL@ utils/customize.pl + +# The default place to find the runtime files is in this directory, +# but it can be overridden with env variables so people can use +# other game directories. +GAMEDIR=game + +update-conf: game/mushcnf.dst game/aliascnf.dst game/restrictcnf.dst game/namescnf.dst + -@@TOUCH@ game/mushcnf.dst + -@@PERL@ utils/update-cnf.pl $(GAMEDIR)/mush.cnf game/mushcnf.dst + -@@TOUCH@ game/aliascnf.dst + -@@PERL@ utils/update-cnf.pl $(GAMEDIR)/alias.cnf game/aliascnf.dst + -@@TOUCH@ game/restrictcnf.dst + -@@PERL@ utils/update-cnf.pl $(GAMEDIR)/restrict.cnf game/restrictcnf.dst + -@if [ ! -f $(GAMEDIR)/names.cnf ]; then $(CP) game/namescnf.dst $(GAMEDIR)/names.cnf; fi + +$(GAMEDIR)/alias.cnf: game/aliascnf.dst + -@@TOUCH@ game/aliascnf.dst + -@@PERL@ utils/update-cnf.pl $(GAMEDIR)/alias.cnf game/aliascnf.dst + +$(GAMEDIR)/restrict.cnf: game/restrictcnf.dst + -@@TOUCH@ game/restrictcnf.dst + -@@PERL@ utils/update-cnf.pl $(GAMEDIR)/restrict.cnf game/restrictcnf.dst + +$(GAMEDIR)/names.cnf: game/namescnf.dst + if [ ! -f game/names.cnf ]; then \ + $(CP) game/namescnf.dst $(GAMEDIR)/names.cnf \ + fi + +$(GAMEDIR)/mush.cnf: game/mushcnf.dst + -@@TOUCH@ game/mushcnf.dst + -@@PERL@ utils/update-cnf.pl $(GAMEDIR)/mush.cnf game/mushcnf.dst + +update: update-hdr update-conf + +update-hdr: + -@@TOUCH@ options.h.dist + -@sleep 2 + -@@PERL@ utils/update.pl options.h options.h.dist + +test: netmud + (cd test; @PERL@ alltests.pl) + +clean: + (cd src; make clean) + (cd game; rm -f netmush info_slave) + +distclean: + (cd hdrs; rm -f *.orig *~ \#* *.rej *.bak funs.h cmds.h buildinf.h patches.h) + (cd utils; rm -f *.orig *~ \#* *.rej *.bak mkcmds.sh *.o) + (cd game; rm -rf *.log netmush info_slave *.orig *.rej *~ *.bak mush.cnf) + (cd src; make distclean; rm -f Makefile) + (cd game/txt; make clean) + (rm -rf .config Makefile config.h config.sh options.h) + +totallyclean: distclean + (cd hdrs; rm -rf *.rej) + (cd src; rm -rf *.rej) + -rm -f Makefile + +diffs: + @make indent > /dev/null 2>&1 + @make versions > /dev/null 2>&1 + @make touchswitches > /dev/null 2>&1 + @make autogen > /dev/null 2>&1 + @(prcs diff -r$(VS) -N cobramush `cat MANIFEST` | grep -v 'Index:') + +commit: indent + @svn commit + +patch: versions + @make-patch-header + @make diffs + +etags: + (cd src; make etags) + +ctags: + (cd src; make ctags) + +touchswitches: + @@TOUCH@ src/SWITCHES + +globalinstall: install + (cd game/txt; make clean compose.sh) +# $(INSTALLDIR) $(GLOBAL_INSTALL) + $(CP) -R game/* $(GLOBAL_INSTALL) + rm -f $(GLOBAL_INSTALL)/netmush $(GLOBAL_INSTALL)/info_slave + $(INSTALL) config.sh $(GLOBAL_INSTALL)/config.sh + $(INSTALL) src/netmud $(GLOBAL_INSTALL)/netmush + $(INSTALL) src/info_slave utils/ln-dir.sh $(GLOBAL_INSTALL) + $(CHMOD) a+rX -R $(GLOBAL_INSTALL) + @echo "** Files installed in $(GLOBAL_INSTALL). Feel free to move them." + @echo "** You can run $(GLOBAL_INSTALL)/ln-dir.sh to create a user directory," + @echo "** or symlink that to somewhere easier to run. You may wish to strip them." + + diff --git a/README.SQL b/README.SQL index c0ff9b3..144195f 100644 --- a/README.SQL +++ b/README.SQL @@ -4,67 +4,119 @@ As of version 1.7.7p32, PennMUSH includes functions and commands that -can access SQL databases. Currently, the following databases are +can access SQL databases. Currently, the following databases are supported: * MySQL + * PostgresQL (from 1.8.3p2) + * Sqlite v3 (from 1.8.3p2) -This document explains how to use (or avoid) SQL with PennMUSH, and covers -the following issues: +This document explains how to use (or avoid) SQL with PennMUSH, and +covers the following issues: I. Compiling with or without SQL II. Mush configuration overview III. SQL setup tips -I. Compiling with MySQL +I. Compiling with/without SQL - The Configure script distributed with PennMUSH automatically detects - the MySQL client library (libmysqlclient) and attempts to link - them into the executable, defining HAS_MYSQL in config.h +In general, Configure attempts to detect all support sql client +libraries on the host, and will link with all of them, permitting you +to select which platform you want at runtime. You can selectively +prevent linking with client libraries that are present on your system, +by passing configure a --without-FOO option. --disable-sql turns off +all checks for SQL servers. + +I.a. MySQL + + The configure script distributed with PennMUSH automatically detects + the MySQL client library via the presence of the mysql_config + program, which will tell configure where needed headers and + libraries are. If you want to avoid linking these libraries on systems where they - are present, use the '-D no_mysql' switch to Configure. + are present, pass the --without-mysql switch to configure. + + If you installed Mysql from a binary package (e.g. rpm or apt), you + should be sure that your system also has the development package + (usuallyl mysql-dev or mysql-devel). - If you installed Mysql from a binary package (e.g. rpm or apt), - you should be sure that your system also has the development - package (usuallyl mysql-dev or mysql-devel). + If you think you have mysql libraries and header files but configure + isn't finding them, they may be in an unusual location on your + system, with mysql_config not in your default path. Find its + location ('where mysql_config' if the program works for you, 'find / + -name mysql_config' otherwise, and call configure with + --with-mysql=/path/to/mysql_config - If you think you have mysql libraries and header files but Configure - isn't finding them, they may be in an unusual location on your system. - Creating symbolic links from the header directory to /usr/include/mysql - and from the libraries in /usr/lib (or adding the mysql library directory - to your /etc/ld.so.conf and running ldconfig) are the easiest ways - to fix this. +I.b. PostgresQL + + The configure script distributed with PennMUSH automatically detects + the PostgresQL client library via the pg_conf program, which will + tell configure where needed headers and libraries are. + + If you want to avoid linking these libraries on systems where they + are present, pass the --without-postgresql switch to configure. + + If you installed PostgresQL from a binary package (e.g. rpm or apt), + you should be sure that your system also has the development package + (usually postgresql-dev, or libpq or similar) + + If you think you have postgresql libraries and header files but + configure isn't finding them, they may be in an unusual location on + your system, with pg_config not in your default path. Find its + location ('where pg_config' if the program works for you, 'find / + -name pg_config' otherwise, and call configure with + --with-postgresql=/path/to/pg_config + +I.c Sqlite + + The configure script distrubted with PennMUSH looks for sqlite3 + headers and libraries in /usr, /usr/local and /opt. If it's + somewhere else on your system, call configure with + --with-sqlite3=/path/to/sqlite3 + + If you want to avoid linking with sqlite on systems where it is + present, pass the --without-sqlite3 switch to configure. + + The path is the directory that contains the hdrs/ and lib/ + directories that hold the sqlite3 headers and library respectively. II. Mush configuration overview mush.cnf includes these directives that configure the SQL support: sql_platform provides the name of the SQL database server software - that will be used for connections. It current takes one of two - values: "disabled" (no SQL) or "mysql". If not specified, it - defaults to disabled. - - sql_host gives the name of the host running the SQL server. - It defaults to 127.0.0.1, which makes a TCP connection to the - local host. The keyword "localhost" instead makes a domain socket - (Unix) or named pipe (Windows) connection. - - sql_database gives the name of the database that contains the - MUSH's tables. This must be specified and there is no default. + that will be used for connections. It current takes one of four + values: "disabled" (no SQL), "mysql", "postgresql", or "sqlite3". + If not specified, it defaults to disabled. + + sql_host gives the name of the host running the SQL server. It + defaults to 127.0.0.1, which makes a TCP connection to the local + host. The keyword "localhost" instead makes a domain socket (Unix) + or named pipe (Windows) connection under MySQL. You can also + specify an alternate port by setting sql_host to hostname:port + (e.g. 127.0.0.1:5444). + + sql_database gives the name of the database that contains the MUSH's + tables. This must be specified and there is no default. sql_username provides a username to connect to the SQL server - with. If no specified, a null username will be used, which many - SQL servers treat as "the user running this (pennmush) process". + with. If no specified, a null username will be used, which many SQL + servers treat as "the user running this (pennmush) process". - sql_password provides the password for the user. It defaults to - no password. + sql_password provides the password for the user. It defaults to no + password. + For sqlite3, which uses a local file instead of connected to a + database server, sql_database gives the name of the database file, + sql_host must be localhost, and the username and password are + currently ignored. + III. SQL setup tips You will have to set up the appropriate database on the SQL server, - and username permitted to perform operations in that database, - and a password for that username. This is a platform-specific process. + and username permitted to perform operations in that database, and a + password for that username. This is a platform-specific process. A. MySQL platform @@ -116,3 +168,24 @@ III. SQL setup tips Are you pretty sure you would like to implement this [yes/no]: yes + B. PostgresQL + + As the postgres user: + + % createuser -A -d -P mush + Enter password for new user: <=========== + CREATE USER + + % createdb -U mush mush + Password: <=========== + CREATE DATABASE + + C. Sqlite3: + + As the same user account that runs the mush: + Edit mush.cnf so that sql_database is set to data/mush.db and + sql_platform is set to sqlite3. + % cd pennmush/game/data + % sqlite3 mush.db + > create table .... + diff --git a/U/Chk_MANI.U b/U/Chk_MANI.U deleted file mode 100644 index 5d4adc8..0000000 --- a/U/Chk_MANI.U +++ /dev/null @@ -1,84 +0,0 @@ -?RCS: $Id: Chk_MANI.U,v 3.0.1.2 1997/02/28 14:57:25 ram Exp $ -?RCS: -?RCS: Copyright (c) 1991-1993, Raphael Manfredi -?RCS: -?RCS: You may redistribute only under the terms of the Artistic Licence, -?RCS: as specified in the README file that comes with the distribution. -?RCS: You may reuse parts of this distribution only within the terms of -?RCS: that same Artistic Licence; a copy of which may be found at the root -?RCS: of the source tree for dist 3.0. -?RCS: -?RCS: $Log: Chk_MANI.U,v $ -?RCS: Revision 3.0.1.2 1997/02/28 14:57:25 ram -?RCS: patch61: added support for src.U -?RCS: -?RCS: Revision 3.0.1.1 1994/10/31 09:33:14 ram -?RCS: patch44: now lists Begin instead of Myinit in its dependencies -?RCS: patch44: leading comment now explains how this unit is included -?RCS: -?RCS: Revision 3.0 1993/08/18 12:04:45 ram -?RCS: Baseline for dist 3.0 netwide release. -?RCS: -?X: -?X: This unit checks the package by making sure every file listed in MANIFEST -?X: is present. It is systematically "included" via the Finish unit (which -?X: is always present in every Configure script), although it may result in -?X: an empty inclusion when no MANIFEST is present. -?X: -?MAKE:Chk_MANI: Begin c n rsrc -?MAKE: -pick wipe $@ %< -?T:filelist ans tmppwd -?X: This check happens at metaconfig-time, so it's ok to hard-code the path. -@if {test -f ../MANIFEST} -: Now test for existence of everything in MANIFEST -echo " " -if test -f $rsrc/MANIFEST; then - echo "First let's make sure your kit is complete. Checking..." >&4 -?X: -?X: Files spelled uppercased and beginning with PACK are produced by the -?X: shell archive builder and may be removed by the user. Usually, they are -?X: not listed in the MANIFEST file, but you never know... -?X: - awk '$1 !~ /PACK[A-Z]+/ {print $1}' $rsrc/MANIFEST | split -l 50 - rm -f missing - tmppwd=`pwd` - for filelist in x??; do - (cd $rsrc; ls `cat $tmppwd/$filelist` >/dev/null 2>>$tmppwd/missing) - done - if test -s missing; then - cat missing >&4 - cat >&4 <<'EOM' - -THIS PACKAGE SEEMS TO BE INCOMPLETE. - -You have the option of continuing the configuration process, despite the -distinct possibility that your kit is damaged, by typing 'y'es. If you -do, don't blame me if something goes wrong. I advise you to type 'n'o -and contact the author (). - -EOM -?X: Can't use $echo at this early stage - echo $n "Continue? [n] $c" >&4 - read ans - case "$ans" in - y*) - echo "Continuing..." >&4 - rm -f missing - ;; - *) -?X: -?X: Use kill and not exit, so that the trap gets executed to clean up -?X: - echo "ABORTING..." >&4 - kill $$ - ;; - esac - else - echo "Looks good..." - fi -else - echo "There is no MANIFEST file. I hope your kit is complete !" -fi -rm -f missing x?? - -@end diff --git a/U/End.U b/U/End.U deleted file mode 100644 index 002c1d5..0000000 --- a/U/End.U +++ /dev/null @@ -1,28 +0,0 @@ -?RCS: $Id: End.U 1.2 Tue, 30 Sep 2003 18:01:23 -0500 dunemush $ -?RCS: -?RCS: Copyright (c) 1991-1993, Raphael Manfredi -?RCS: -?RCS: You may redistribute only under the terms of the Artistic Licence, -?RCS: as specified in the README file that comes with the distribution. -?RCS: You may reuse parts of this distribution only within the terms of -?RCS: that same Artistic Licence; a copy of which may be found at the root -?RCS: of the source tree for dist 3.0. -?RCS: -?RCS: $Log: End.U,v $ -?RCS: Revision 3.0 1993/08/18 12:04:51 ram -?RCS: Baseline for dist 3.0 netwide release. -?RCS: -?X: -?X: This unit serves as the goal which forces make to choose all the units that -?X: ask questions. The $W on the ?MAKE: line is the list of all symbols wanted. -?X: To force any unit to be included, copy this unit to your private U directory -?X: and add the name of the unit desired to the ?MAKE: dependency line. -?X: -?MAKE:End: $W d_tcl MailList -?MAKE: -pick add $@ %< -?LINT:use $W d_tcl MailList -: end of configuration questions -echo " " -echo "End of configuration questions." -echo " " - diff --git a/U/Findhdr.U b/U/Findhdr.U deleted file mode 100644 index 11e9578..0000000 --- a/U/Findhdr.U +++ /dev/null @@ -1,124 +0,0 @@ -?RCS: $Id: Findhdr.U 1.1 Thu, 20 Jul 2000 17:42:54 -0500 dunemush $ -?RCS: -?RCS: Copyright (c) 1991-1993, Raphael Manfredi -?RCS: -?RCS: You may redistribute only under the terms of the Artistic Licence, -?RCS: as specified in the README file that comes with the distribution. -?RCS: You may reuse parts of this distribution only within the terms of -?RCS: that same Artistic Licence; a copy of which may be found at the root -?RCS: of the source tree for dist 3.0. -?RCS: -?RCS: Original Author: Thomas Neumann -?RCS: -?RCS: $Log: Findhdr.U,v $ -?RCS: Revision 1.2 1997/11/25 18:41:56 popiel -?RCS: From dist -?RCS: -?RCS: Revision 3.0.1.2 1994/10/29 15:53:08 ram -?RCS: patch36: added ?F: line for metalint file checking -?RCS: -?RCS: Revision 3.0.1.1 1994/05/06 14:03:56 ram -?RCS: patch23: cppminus must be after other cppflags, not before -?RCS: -?RCS: Revision 3.0 1993/08/18 12:04:54 ram -?RCS: Baseline for dist 3.0 netwide release. -?RCS: -?X: -?X: This unit produces a findhdr script which is used to locate the header -?X: files in $usrinc or other stranger places using cpp capabilities. The -?X: script is given an include file base name, like 'stdio.h' or 'sys/file.h' -?X: and it returns the full path of the include file and a zero status or an -?X: empty string with an error status if the file could not be located. -?X: -?MAKE:Findhdr: grep test tr rm +usrinc awk cat startsh \ - cppstdin cppminus +cppflags -?MAKE: -pick add $@ %< -?LINT:define fieldn -?S:fieldn: -?S: This variable is used internally by Configure. It contains the position -?S: of the included file name in cpp output. That is to say, when cpp -?S: pre-processes a #include line, it replaces it by a # line which -?S: contains the original position in the input file and the full name of -?S: included file, between "quotes". -?S:. -?V:fieldn -?F:./findhdr !fieldn -?T:cline pos wanted name awkprg -: determine filename position in cpp output -echo " " -echo "Computing filename position in cpp output for #include directives..." >&4 -echo '#include ' > foo.c -$cat >fieldn </dev/null | \ -$grep '^[ ]*#.*stdio\.h' | \ -while read cline; do - pos=1 -?X: We have to go through this nightmare of sed and eval because some -?X: folks like putting spaces in their directory names, which then get -?X: echoed into the paths to standard headers. Thanks, Microsoft! -?X: -?X: What we're doing here is escaping every single shell meta-character -?X: except for quotation marks, then evaluating that as an argument list. - qline=\`echo "\$cline" | $sed -e 's/\\([][{}#$<>;&()|^*?\\\\]\\)/\\\\\\\\\\1/g'\` - eval set \$qline - while $test "x\$1" \!= x; do - if $test -r "\$1"; then - echo "\$pos" - exit 0 - fi - shift - pos=\`expr \$pos + 1\` - done -done -EOF -chmod +x fieldn -fieldn=`./fieldn` -$rm -f foo.c fieldn -case $fieldn in -'') pos='???';; -1) pos=first;; -2) pos=second;; -3) pos=third;; -*) pos="${fieldn}th";; -esac -echo "Your cpp writes the filename in the $pos field of the line." - -?X: To locate a header file, we cannot simply check for $usrinc/file.h, since -?X: some machine have the headers in weird places and our only hope is that -?X: the C pre-processor will know how to find those headers. Thank you NexT! -: locate header file -$cat >findhdr <" > foo\$\$.c -$cppstdin $cppminus $cppflags < foo\$\$.c 2>/dev/null | \ -$grep "^[ ]*#.*\$wanted" | \ -while read cline; do - pos=1 - qline=\`echo "\$cline" | $sed -e 's/\\([][{}#$<>;&()|^'"'"'*?\\\\]\\)/\\\\\\\\\\1/g'\` - eval set \$qline - while $test $fieldn -gt \$pos; do - shift - pos=\`expr \$pos + 1\` - done - name=\$1 - case "\$name" in - */\$wanted) echo "\$name"; exit 0;; -?X: Of course, Microsoft likes backslashes, too. @whee. - *\\\\\$wanted) echo "\$name"; exit 0;; - *) name='';; - esac; -done; -$rm -f foo\$\$.c; -case "\$name" in -'') exit 1;; -esac -EOF -chmod +x findhdr - diff --git a/U/Guess.U b/U/Guess.U deleted file mode 100644 index 849b98e..0000000 --- a/U/Guess.U +++ /dev/null @@ -1,133 +0,0 @@ -?RCS: $Id: Guess.U 1.1 Thu, 20 Jul 2000 17:42:54 -0500 dunemush $ -?RCS: -?RCS: Copyright (c) 1991-1993, Raphael Manfredi -?RCS: -?RCS: You may redistribute only under the terms of the Artistic Licence, -?RCS: as specified in the README file that comes with the distribution. -?RCS: You may reuse parts of this distribution only within the terms of -?RCS: that same Artistic Licence; a copy of which may be found at the root -?RCS: of the source tree for dist 3.0. -?RCS: -?RCS: $Log: Guess.U,v $ -?RCS: Revision 3.0.1.4 1994/10/29 15:53:55 ram -?RCS: patch36: added ?F: line for metalint file checking -?RCS: patch36: call ./xenix explicitely instead of relying on PATH -?RCS: -?RCS: Revision 3.0.1.3 1993/12/15 08:14:35 ram -?RCS: patch15: variable d_bsd was not always set properly -?RCS: -?RCS: Revision 3.0.1.2 1993/08/30 08:57:14 ram -?RCS: patch8: fixed comment which wrongly attributed the usrinc symbol -?RCS: patch8: no more ugly messages when no /usr/include/ctype.h -?RCS: -?RCS: Revision 3.0.1.1 1993/08/27 14:37:37 ram -?RCS: patch7: added support for OSF/1 machines -?RCS: -?RCS: Revision 3.0 1993/08/18 12:04:57 ram -?RCS: Baseline for dist 3.0 netwide release. -?RCS: -?X: -?X: This unit hazards some guesses as to what the general nature of the system -?X: is. The information it collects here is used primarily to establish default -?X: answers to other questions. -?X: -?MAKE:Guess d_eunice d_xenix d_bsd: cat test echo n c contains rm Loc eunicefix -?MAKE: -pick add $@ %< -?S:d_eunice: -?S: This variable conditionally defines the symbols EUNICE and VAX, which -?S: alerts the C program that it must deal with ideosyncracies of VMS. -?S:. -?S:d_xenix: -?S: This variable conditionally defines the symbol XENIX, which alerts -?S: the C program that it runs under Xenix. -?S:. -?S:d_bsd: -?S: This symbol conditionally defines the symbol BSD when running on a -?S: BSD system. -?S:. -?F:./bsd ./usg ./v7 ./osf1 ./eunice ./xenix ./venix -?T:xxx -: make some quick guesses about what we are up against -echo " " -$echo $n "Hmm... $c" -echo exit 1 >bsd -echo exit 1 >usg -echo exit 1 >v7 -echo exit 1 >osf1 -echo exit 1 >eunice -echo exit 1 >xenix -echo exit 1 >venix -d_bsd="$undef" -?X: -?X: Do not use 'usrinc', or we get a circular dependency. because -?X: usrinc is defined in usrinc.U, which relies on us... -?X: -$cat /usr/include/signal.h /usr/include/sys/signal.h >foo 2>/dev/null -if test -f /osf_boot || $contains 'OSF/1' /usr/include/ctype.h >/dev/null 2>&1 -then - echo "Looks kind of like an OSF/1 system, but we'll see..." - echo exit 0 >osf1 -elif test `echo abc | tr a-z A-Z` = Abc ; then - xxx=`./loc addbib blurfl $pth` - if $test -f $xxx; then - echo "Looks kind of like a USG system with BSD features, but we'll see..." - echo exit 0 >bsd - echo exit 0 >usg - else - if $contains SIGTSTP foo >/dev/null 2>&1 ; then - echo "Looks kind of like an extended USG system, but we'll see..." - else - echo "Looks kind of like a USG system, but we'll see..." - fi - echo exit 0 >usg - fi -elif $contains SIGTSTP foo >/dev/null 2>&1 ; then - echo "Looks kind of like a BSD system, but we'll see..." - d_bsd="$define" - echo exit 0 >bsd -else - echo "Looks kind of like a Version 7 system, but we'll see..." - echo exit 0 >v7 -fi -case "$eunicefix" in -*unixtovms*) - $cat <<'EOI' -There is, however, a strange, musty smell in the air that reminds me of -something...hmm...yes...I've got it...there's a VMS nearby, or I'm a Blit. -EOI - echo exit 0 >eunice - d_eunice="$define" -: it so happens the Eunice I know will not run shell scripts in Unix format - ;; -*) - echo " " - echo "Congratulations. You aren't running Eunice." - d_eunice="$undef" - ;; -esac -if test -f /xenix; then - echo "Actually, this looks more like a XENIX system..." - echo exit 0 >xenix - d_xenix="$define" -else - echo " " - echo "It's not Xenix..." - d_xenix="$undef" -fi -chmod +x xenix -$eunicefix xenix -if test -f /venix; then - echo "Actually, this looks more like a VENIX system..." - echo exit 0 >venix -else - echo " " - if ./xenix; then - : null - else - echo "Nor is it Venix..." - fi -fi -chmod +x bsd usg v7 osf1 eunice xenix venix -$eunicefix bsd usg v7 osf1 eunice xenix venix -$rm -f foo - diff --git a/U/Head.U b/U/Head.U deleted file mode 100644 index e887142..0000000 --- a/U/Head.U +++ /dev/null @@ -1,278 +0,0 @@ -?RCS: $Id: Head.U 1.3 Mon, 10 Nov 2003 14:51:32 -0600 dunemush $ -?RCS: -?RCS: Copyright (c) 1991-1993, Raphael Manfredi -?RCS: -?RCS: You may redistribute only under the terms of the Artistic Licence, -?RCS: as specified in the README file that comes with the distribution. -?RCS: You may reuse parts of this distribution only within the terms of -?RCS: that same Artistic Licence; a copy of which may be found at the root -?RCS: of the source tree for dist 3.0. -?RCS: -?RCS: $Log: Head.U,v $ -?RCS: Revision 1.2 1997/11/25 18:08:08 popiel -?RCS: From dist. -?RCS: -?RCS: Revision 3.0.1.9 1997/02/28 15:02:09 ram -?RCS: patch61: make sure we unset CDPATH for shells that support this -?RCS: patch61: improved Korn shell detection and handling -?RCS: -?RCS: Revision 3.0.1.8 1995/07/25 13:40:02 ram -?RCS: patch56: added SVR4-ish /opt directories to path list (ADO) -?RCS: patch56: OS/2 platforms are using another path separator -?RCS: -?RCS: Revision 3.0.1.7 1995/03/21 08:46:15 ram -?RCS: patch52: definition of paths wrongly added spurious ':' chars -?RCS: -?RCS: Revision 3.0.1.6 1994/10/29 15:54:19 ram -?RCS: patch36: make sure ENV is unset before calling /bin/ksh -?RCS: -?RCS: Revision 3.0.1.5 1994/08/29 16:03:44 ram -?RCS: patch32: now sets PATH only using existing directories -?RCS: -?RCS: Revision 3.0.1.4 1994/06/20 06:54:28 ram -?RCS: patch30: now computes its invocation name into 'me' -?RCS: patch30: symbol me is made visible to all units read-only -?RCS: -?RCS: Revision 3.0.1.3 1993/12/15 08:15:07 ram -?RCS: patch15: added /sbin:/usr/sbin:/usr/libexec in PATH for BSD/386 -?RCS: -?RCS: Revision 3.0.1.2 1993/11/10 17:32:35 ram -?RCS: patch14: ensure PATH is reset to '.' before testing for alias -?RCS: -?RCS: Revision 3.0.1.1 1993/08/27 14:38:07 ram -?RCS: patch7: not all 'test' programs support the -x option -?RCS: -?RCS: Revision 3.0 1993/08/18 12:04:58 ram -?RCS: Baseline for dist 3.0 netwide release. -?RCS: -?X: -?X: This is the very first unit in the Configure script. It is mostly just -?X: things to keep people from getting into a tizzy right off the bat. -?X: -?MAKE:Head: -?MAKE: -pick wipe $@ %< -?V:PATH p_ me -?T:argv Id p paths OS2_SHELL -?T:inksh needksh avoidksh newsh changesh reason -#! /bin/sh -# -# If these # comments don't work, trim them. Don't worry about any other -# shell scripts, Configure will trim # comments from them for you. -# -# (If you are trying to port this package to a machine without sh, -# I would suggest you have a look at the prototypical config_h.SH file -# and edit it to reflect your system. Some packages may include samples -# of config.h for certain machines, so you might look for one of those.) -# -?X: -?X: NOTE THAT A CONFIGURE SCRIPT IS IN THE PUBLIC DOMAIN (whether or not -?X: the software which uses it is in the public domain). -?X: -# Yes, you may rip this off to use in other distribution packages. This -# script belongs to the public domain and cannot be copyrighted. -# -?X: -?X: WE ASK YOU NOT TO REMOVE OR ALTER THE FOLLOWING PARAGRAPH, PLEASE: -?X: -# (Note: this Configure script was generated automatically. Rather than -# working with this copy of Configure, you may wish to get metaconfig. -# The dist-3.0 package (which contains metaconfig) was posted in -# comp.sources.misc and is available on CPAN under authors/id/RAM so -# you may fetch it yourself from your nearest archive site.) -# -?X: -?X: NOTA BENE: -?X: If you develop you own version of metaconfig based on this work, -?X: you have to add some comments telling that the script was generated -?X: by your version, not mine: It credits your work. -?X: - -# $Id: Head.U 1.3 Mon, 10 Nov 2003 14:51:32 -0600 dunemush $ -# -# Generated on [metaconfig ] - -cat >/tmp/c1$$ </tmp/c2$$ </dev/null` - test "$me" || me=$0 - ;; -esac - -?X: -?X: To be able to run under OS/2, we must detect that early enough to use -?X: the proper path separator, stored in $p_. It is : on UNIX and \ on OS/2. -?X: However, we have to be careful not to confuse with win32 running the -?X: cygwin32 unix emulation tools. -?X: -: Proper PATH separator -p_=: -: On OS/2 this directory should exist if this is not floppy only system :-] -if test -d c:/.; then - : Check for cygwin32 emulation - case "x$OSTYPE$OS" in - x*msys*Windows*) - echo 'Running on Windows? Using the MinGW MSys tools...' - ;; - x*win32*) - echo 'Running on Windows? Assuming cygwin32 emulation tools...' - ;; - x*windows*) - echo 'Running on Windows? Assuming cygwin32 emulation tools...' - ;; - x*cygwin*) - echo 'Looks like cygwin32...' - ;; - x*) - p_=\; - PATH=`cmd /c "echo %PATH%" | tr '\\\\' / ` -?X: That's a bug in ksh5.22 - OS2_SHELL=`cmd /c "echo %OS2_SHELL%" | tr '\\\\' / | tr '[A-Z]' '[a-z]'` - ;; - esac -fi - -?X: -?X: There are two schools of thoughts here. Some people correctly argue that -?X: the user has a better chance than we do of setting a reasonable PATH and -?X: others argue that Configure is the best place there is to set up a suitable -?X: PATH. Well, here we try to compromize by keeping the user's PATH and -?X: appending some directories which are known to work on some machine or the -?X: other. The rationale behind this being that a novice user might not have a -?X: proper environment variable set, and some directories like /etc (where -?X: chown is located on some BSD systems) may be missing--RAM. -?X: -?X: SVR4 adds an /opt directory for optional packages. Some sites use -?X: various permutations on /opt as opposed to /usr or /usr/local.-- ADO -?X: -?X: cygwin32 strongly suggests /gnuwin32/b18/H-i386-cygwin32/bin. Talk -?X: about ugly. -?X: -?X: We only add directories that are not already in the PATH of the -?X: user and the directories must exist also. -?X: -: Proper PATH setting -paths='/bin /usr/bin /usr/local/bin /usr/ucb /usr/local /usr/lbin' -paths="$paths /opt/bin /opt/local/bin /opt/local /opt/lbin" -paths="$paths /usr/5bin /etc /usr/gnu/bin /usr/new /usr/new/bin /usr/nbin" -paths="$paths /opt/gnu/bin /opt/new /opt/new/bin /opt/nbin" -paths="$paths /sys5.3/bin /sys5.3/usr/bin /bsd4.3/bin /bsd4.3/usr/ucb" -paths="$paths /bsd4.3/usr/bin /usr/bsd /bsd43/bin /usr/ccs/bin" -paths="$paths /etc /usr/lib /usr/ucblib /lib /usr/ccs/lib" -paths="$paths /sbin /usr/sbin /usr/libexec /gnuwin32/b18/H-i386-cygwin32/bin" - -case "x$OSTYPE$OS" in - x*msys*Windows*) - PATH='/usr/local/bin:/mingw/bin:/bin:/perl/bin' - ;; - x*) - for p in $paths - do - case "$p_$PATH$p_" in - *$p_$p$p_*) ;; - *) test -d $p && PATH=$PATH$p_$p ;; - esac - done - - PATH=.$p_$PATH - export PATH - ;; -esac - -: shall we be using ksh? -inksh='' -needksh='' -avoidksh='' -newsh=/bin/ksh -changesh='' -?X: Use (alias -x) and not (alias) since zsh and bash recognize the alias -?X: builtin but not the -x option which is typically ksh... -?X: We need to set up PATH before calling the "alias" built-in since some -?X: systems like HP-UX have a binary called /bin/alias. -if (PATH=.; alias -x) >/dev/null 2>&1; then - inksh=true -fi -?X: On HP-UX, large Configure scripts may exercise a bug in /bin/sh, use ksh -if test -f /hp-ux -a -f /bin/ksh; then - needksh='to avoid sh bug in "here document" expansion' -fi -?X: On AIX4, /bin/sh is really ksh and it causes problems, use sh -if test -d /usr/lpp -a -f /usr/bin/bsh -a -f /usr/bin/uname; then - if test X`/usr/bin/uname -v` = X4; then - avoidksh="to avoid AIX 4's /bin/sh" - newsh=/usr/bin/bsh - fi -fi -?X: If we are not in ksh and need it, then feed us back to it -case "$inksh/$needksh" in -/[a-z]*) -?X: Unset ENV to avoid any ~/.kshrc that could alias cd or whatever... - unset ENV - changesh=true - reason="$needksh" - ;; -esac -?X: If we are in ksh and must avoid it, then feed us back to a new shell -case "$inksh/$avoidksh" in -true/[a-z]*) - changesh=true - reason="$avoidksh" - ;; -esac -?X: Warn them if they use ksh on other systems, which are those where -?X: we don't need ksh nor want to avoid it explicitely, yet are using it. -case "$inksh/$needksh-$avoidksh-" in -true/--) - cat <&4 -cat <loc -$startsh -case \$# in -0) exit 1;; -esac -thing=\$1 -shift -dflt=\$1 -shift -for dir in \$*; do - case "\$thing" in - .) - if test -d \$dir/\$thing; then - echo \$dir - exit 0 - fi - ;; - *) -?X: Be careful in case thing includes wildcards that might expand to multiple -?X: files. Choose the last one. This happens when searching for shared -?X: libraries with version numbers. How to choose which one we want is -?X: probably an insoluble problem, in general. -?X: Some folks leave things like libc.so.orig around w/o read -?X: permission. A -r test would handle that, but since ./loc is -?X: also used to find executables (which are installed w/o read -?X: permission on SCO ODT 3.0, we can't include the -r test. - for thisthing in \$dir/\$thing; do - : just loop through to pick last item - done - if test -f \$thisthing; then - echo \$thisthing - exit 0 - elif test -f \$dir/\$thing.exe; then - : on Eunice apparently - echo \$dir/\$thing - exit 0 - fi - ;; - esac -done -echo \$dflt -exit 1 -EOSC -chmod +x loc -$eunicefix loc -loclist=" -?awk:awk -?cat:cat -?chgrp:chgrp -?chmod:chmod -?chown:chown -?comm:comm -?cp:cp -?echo:echo -?expr:expr -?find:find -?grep:grep -?ls:ls -?make:make -?mkdir:mkdir -?mv:mv -?rm:rm -?sed:sed -?sleep:sleep -?sort:sort -?tail:tail -?touch:touch -?tr:tr -?uniq:uniq -" -trylist=" -?Mcc:Mcc -?ar:ar -?bash:bash -?bison:bison -?byacc:byacc -?compress:compress -?cpio:cpio -?cpp:cpp -?csh:csh -?date:date -?egrep:egrep -?emacs:emacs -?flex:flex -?gcc:gcc -?gzip:gzip -?inews:inews -?ksh:ksh -?less:less -?line:line -?lint:lint -?ln:ln -?lp:lp -?lpr:lpr -?mail:mail -?mailx:mailx -?more:more -?nroff:nroff -?perl:perl -?pg:pg -?pmake:pmake -?pr:pr -?rmail:rmail -?sendmail:sendmail -?shar:shar -?smail:smail -?submit:submit -?tar:tar -?tbl:tbl -?test:test -?troff:troff -?uname:uname -?uptime:uptime -?uuname:uuname -?vi:vi -?zcat:zcat -?zip:zip -" -?LINT:set Loc Mcc awk ar bash bison byacc cat chgrp chmod chown \ - comm compress cp cpio cpp csh date echo egrep emacs expr find flex \ - gcc gzip grep inews ksh less line lint ln lp lpr ls mail mailx \ - make mkdir more mv nroff perl pg pmake pr rm rmail sed sendmail \ - shar sleep smail sort submit tail tar tbl test touch tr troff \ - uname uniq uptime uuname vi zcat zip -pth=`echo $PATH | sed -e "s/$p_/ /g"` -pth="$pth /lib /usr/lib" -for file in $loclist; do -?X: -?X: Allow them to -Dmake=pmake on the command line for instance... -?X: If the file is not fully qualified, as in -Dmake=pmake, then we -?X: look the for the specified command (pmake here). If they say -?X: -Dmake=/sbin/make for instance, then we make sure the file -?X: exists, or we die... -?X: - eval xxx=\$$file - case "$xxx" in - /*|?:[\\/]*) - if test -f "$xxx"; then - : ok - else - echo "WARNING: no $xxx -- ignoring your setting for $file." >&4 - xxx=`./loc $file $file $pth` - fi - ;; - '') xxx=`./loc $file $file $pth`;; - *) xxx=`./loc $xxx $xxx $pth`;; - esac - eval $file=$xxx - eval _$file=$xxx - case "$xxx" in - /*) - echo $file is in $xxx. - ;; -?X: Under OS/2, we have PC-like paths - ?:[\\/]*) - echo $file is in $xxx. - ;; - *) - echo "I don't know where '$file' is, and my life depends on it." >&4 - echo "Go find a public domain implementation or fix your PATH setting!" >&4 - exit 1 - ;; - esac -done -echo " " -echo "Don't worry if any of the following aren't found..." -say=offhand -for file in $trylist; do -?X: Allow them to -Dmake=pmake on the command line for instance (see above) - eval xxx=\$$file - case "$xxx" in - /*|?:[\\/]*) - if test -f "$xxx"; then - : ok - else - echo "WARNING: no $xxx -- ignoring your setting for $file." >&4 - xxx=`./loc $file $file $pth` - fi - ;; - '') xxx=`./loc $file $file $pth`;; - *) xxx=`./loc $xxx $xxx $pth`;; - esac - eval $file=$xxx - eval _$file=$xxx - case "$xxx" in - /*) - echo $file is in $xxx. - ;; -?X: Under OS/2, we have PC-like paths - ?:[\\/]*) - echo $file is in $xxx. - ;; - *) - echo "I don't see $file out there, $say." - say=either - ;; - esac -done -case "$egrep" in -egrep) - echo "Substituting grep for egrep." - egrep=$grep - ;; -esac -@if ln -case "$ln" in -ln) - echo "Substituting cp for ln." - ln=$cp - ;; -esac -@end -case "$test" in -test) - echo "Hopefully test is built into your sh." - ;; -*) - if `sh -c "PATH= test true" >/dev/null 2>&1`; then - echo "Using the test built into your sh." -?X: -?X: We need to set both test and _test, since Oldconfig.U will use the _test -?X: value to systematically restore computed paths, which may be wrong if -?X: we choose to load an old config.sh generated on another platform. -?X: - test=test - _test=test - fi - ;; -esac -?LINT:change n c -case "$echo" in -echo) - echo "Hopefully echo is built into your sh." - ;; -?X: For those rare cases where we don't need $echo... -'') ;; -*) - echo " " -echo "Checking compatibility between $echo and builtin echo (if any)..." >&4 - $echo $n "hi there$c" >foo1 - echo $n "hi there$c" >foo2 - if cmp foo1 foo2 >/dev/null 2>&1; then - echo "They are compatible. In fact, they may be identical." - else - case "$n" in - '-n') n='' c='\c';; - *) n='-n' c='';; - esac - cat <$c" - $echo "*" - fi - $rm -f foo1 foo2 - ;; -esac - diff --git a/U/MailList.U b/U/MailList.U deleted file mode 100644 index 833aea8..0000000 --- a/U/MailList.U +++ /dev/null @@ -1,82 +0,0 @@ -?RCS: $Id: MailList.U 1.1 Thu, 20 Jul 2000 17:42:54 -0500 dunemush $ -?RCS: -?RCS: Copyright (c) 1991-1993, Raphael Manfredi -?RCS: -?RCS: You may redistribute only under the terms of the Artistic Licence, -?RCS: as specified in the README file that comes with the distribution. -?RCS: You may reuse parts of this distribution only within the terms of -?RCS: that same Artistic Licence; a copy of which may be found at the root -?RCS: of the source tree for dist 3.0. -?RCS: -?RCS: Original Author: Graham Stoney -?RCS: -?RCS: $Log: MailList.U,v $ -?RCS: Revision 3.0.1.1 1994/01/24 14:01:49 ram -?RCS: patch16: created -?RCS: -?RCS: -?X: -?X: This unit offers the user the option of subscribing to the mailing -?X: list. To force inclusion of this unit, you must add it's name to the -?X: dependancies on the MAKE line in your private copy of End.U. -?X: The address of the mailing list server must be set via a "list_request=..." -?X: entry in the .package file. This is usually done by running packinit and -?X: answering the proper questions. -?X: -?MAKE:MailList: cat mailer package Myread cf_name cf_email -?MAKE: -pick wipe $@ %< -?T:list_request list_sub list_unsub list_name -?X: -?X: The cf_name dependency is used through list_sub when the mailing list -?X: manager happens to be listserv, whereas cf_email is used whith majordomo -?X: or when the mailing list request address is scanned by a human. Since -?X: they do not appear within the unit itself, we need a lint hint. -?X: -?LINT:use cf_name cf_email -: offer to join the mailing list -list_request='<$list_request>' -list_sub="<$list_sub>" -list_unsub="<$list_unsub>" -list_name="<$list_name>" -$cat <&4 - $mailer $list_request </dev/null 2>&1 -To: $list_request -Subject: Subscription request by configure - -$list_sub -EOM - ;; -[uU]*) echo "Sending mail to unsubscribe you from the $list_name list..." >&4 - $mailer $list_request </dev/null 2>&1 -To: $list_request -Subject: Unsubscription request by configure - -$list_unsub -EOM - ;; -esac - diff --git a/U/Myinit.U b/U/Myinit.U deleted file mode 100644 index abd5e02..0000000 --- a/U/Myinit.U +++ /dev/null @@ -1,30 +0,0 @@ -?RCS: $Id: Myinit.U 1.5 Sun, 02 Feb 2003 10:43:44 -0600 dunemush $ -?RCS: -?RCS: Copyright (c) 1991-1993, Raphael Manfredi -?RCS: -?RCS: You may redistribute only under the terms of the Artistic Licence, -?RCS: as specified in the README file that comes with the distribution. -?RCS: You may reuse parts of this distribution only within the terms of -?RCS: that same Artistic Licence; a copy of which may be found at the root -?RCS: of the source tree for dist 3.0. -?RCS: -?RCS: $Log: Myinit.U,v $ -?RCS: Revision 3.0.1.1 1994/10/31 09:47:29 ram -?RCS: patch44: leading comment states this unit comes before option processing -?RCS: -?RCS: Revision 3.0 1993/08/18 12:05:07 ram -?RCS: Baseline for dist 3.0 netwide release. -?RCS: -?X: -?X: If you want to initialize any default values, copy this unit to your -?X: personal U directory and add the assignments to the end. This file -?X: is included after variables are initialized but before any old -?X: config.sh file is read in and before any Configure switch processing. -?X: -?MAKE:Myinit: Init -?MAKE: -pick add $@ %< -?LINT:set defvoidused libswanted toplev -?INIT:toplev=`cd ..;pwd` -defvoidused=15 -libswanted='nsl socket m c crypt bind resolv ld dl tcl intl' - diff --git a/U/Oldconfig.U b/U/Oldconfig.U deleted file mode 100644 index 3152c7a..0000000 --- a/U/Oldconfig.U +++ /dev/null @@ -1,623 +0,0 @@ -?RCS: $Id: Oldconfig.U 1.3 Mon, 28 Jun 2004 09:20:49 -0500 dunemush $ -?RCS: -?RCS: Copyright (c) 1991-1993, Raphael Manfredi -?RCS: -?RCS: You may redistribute only under the terms of the Artistic Licence, -?RCS: as specified in the README file that comes with the distribution. -?RCS: You may reuse parts of this distribution only within the terms of -?RCS: that same Artistic Licence; a copy of which may be found at the root -?RCS: of the source tree for dist 3.0. -?RCS: -?RCS: $Log: Oldconfig.U,v $ -?RCS: Revision 1.2 1997/11/25 18:20:23 popiel -?RCS: From dist -?RCS: -?RCS: Revision 3.0.1.10 1997/02/28 15:06:39 ram -?RCS: patch61: added support for src.U -?RCS: patch61: new OSNAME define -?RCS: patch61: can now sense new OSes -?RCS: -?RCS: Revision 3.0.1.9 1995/07/25 13:40:51 ram -?RCS: patch56: now knows about OS/2 platforms -?RCS: -?RCS: Revision 3.0.1.8 1995/05/12 12:04:18 ram -?RCS: patch54: config.sh reload logic now knows about new -K switch -?RCS: patch54: cleaned up and extended osvers for DEC OSF/1 (ADO) -?RCS: patch54: added MachTen detection (ADO) -?RCS: -?RCS: Revision 3.0.1.7 1995/02/15 14:13:41 ram -?RCS: patch51: adapted osvers computation for AIX (ADO) -?RCS: -?RCS: Revision 3.0.1.6 1995/01/30 14:27:15 ram -?RCS: patch49: unit Options.U now exports file optdef.sh, not a variable -?RCS: patch49: update code for myuname changed (WED) -?RCS: -?RCS: Revision 3.0.1.5 1995/01/11 15:15:36 ram -?RCS: patch45: added quotes around the INITPROG variable (ADO) -?RCS: patch45: allows variable overriding after config file loading -?RCS: -?RCS: Revision 3.0.1.4 1994/10/29 15:57:05 ram -?RCS: patch36: added ?F: line for metalint file checking -?RCS: patch36: merged with the version used for perl5's Configure (ADO) -?RCS: -?RCS: Revision 3.0.1.3 1994/05/06 14:24:17 ram -?RCS: patch23: added support for osf1 hints -?RCS: patch23: new support for solaris and i386 systems (ADO) -?RCS: -?RCS: Revision 3.0.1.2 1994/01/24 14:05:02 ram -?RCS: patch16: added post-processing on myuname for Xenix targets -?RCS: patch16: message proposing config.sh defaults made consistent -?RCS: -?RCS: Revision 3.0.1.1 1993/09/13 15:56:32 ram -?RCS: patch10: force use of config.sh when -d option is used (WAD) -?RCS: patch10: complain about non-existent hint files (WAD) -?RCS: patch10: added Options dependency for fastread variable -?RCS: -?RCS: Revision 3.0 1993/08/18 12:05:12 ram -?RCS: Baseline for dist 3.0 netwide release. -?RCS: -?X: -?X: This unit tries to remember what we did last time we ran Configure, mostly -?X: for the sake of setting defaults. -?X: -?MAKE:Oldconfig hint myuname osname osvers: Instruct Myread uname \ - sh awk sed test cat rm lns n c contains Loc Options Tr src -?MAKE: -pick wipe $@ %< -?S:myuname: -?S: The output of 'uname -a' if available, otherwise the hostname. On Xenix, -?S: pseudo variables assignments in the output are stripped, thank you. The -?S: whole thing is then lower-cased. -?S:. -?S:hint: -?S: Gives the type of hints used for previous answers. May be one of -?S: "default", "recommended" or "previous". -?S:. -?S:osname: -?S: This variable contains the operating system name (e.g. sunos, -?S: solaris, hpux, etc.). It can be useful later on for setting -?S: defaults. Any spaces are replaced with underscores. It is set -?S: to a null string if we can't figure it out. -?S:. -?S:osvers: -?S: This variable contains the operating system version (e.g. -?S: 4.1.3, 5.2, etc.). It is primarily used for helping select -?S: an appropriate hints file, but might be useful elsewhere for -?S: setting defaults. It is set to '' if we can't figure it out. -?S: We try to be flexible about how much of the version number -?S: to keep, e.g. if 4.1.1, 4.1.2, and 4.1.3 are essentially the -?S: same for this package, hints files might just be os_4.0 or -?S: os_4.1, etc., not keeping separate files for each little release. -?S:. -?C:OSNAME: -?C: This symbol contains the name of the operating system, as determined -?C: by Configure. You shouldn't rely on it too much; the specific -?C: feature tests from Configure are generally more reliable. -?C:. -?H:#define OSNAME "$osname" /**/ -?H:. -?F:!config.sh -?T:tmp tmp_n tmp_c tmp_sh file -?T:xxxxfile xxxfile xxfile xfile hintfile newmyuname -?T:tans _ isesix INITPROG -?LINT:change n c sh -: Try to determine whether config.sh was made on this system -case "$config_sh" in -'') -?X: indentation wrong on purpose--RAM -?X: Leave a white space between first two '(' for ksh. The sub-shell is needed -?X: on some machines to avoid the error message when uname is not found; e.g. -?X: old SUN-OS 3.2 would not execute hostname in (uname -a || hostname). Sigh! -myuname=`( ($uname -a) 2>/dev/null || hostname) 2>&1` -?X: Special mention for Xenix, whose 'uname -a' gives us output like this: -?X: sysname=XENIX -?X: nodename=whatever -?X: release=2.3.2 .. etc... -?X: Therefore, we strip all this variable assignment junk and remove all the -?X: new lines to keep the myuname variable sane... --RAM -myuname=`echo $myuname | $sed -e 's/^[^=]*=//' -e 's/\///g' | \ - ./tr '[A-Z]' '[a-z]' | tr '\012' ' '` -?X: Save the value we just computed to reset myuname after we get done here. -newmyuname="$myuname" -dflt=n -case "$knowitall" in -'') - if test -f ../config.sh; then - if $contains myuname= ../config.sh >/dev/null 2>&1; then - eval "`grep myuname= ../config.sh`" - fi - if test "X$myuname" = "X$newmyuname"; then - dflt=y - fi - fi - ;; -*) dflt=y;; -esac - -@if {test -d ../hints} -: Get old answers from old config file if Configure was run on the -: same system, otherwise use the hints. -hint=default -cd .. -?X: Since we are now at the root of the source tree, we must use $src -?X: to access the sources and not $rsrc. See src.U for details... -if test -f config.sh; then - echo " " - rp="I see a config.sh file. Shall I use it to set the defaults?" - . UU/myread - case "$ans" in - n*|N*) echo "OK, I'll ignore it."; mv config.sh config.sh.old;; - *) echo "Fetching default answers from your old config.sh file..." >&4 - tmp_n="$n" - tmp_c="$c" - tmp_sh="$sh" - . ./config.sh - cp config.sh UU - n="$tmp_n" - c="$tmp_c" - : Older versions did not always set $sh. Catch re-use of such - : an old config.sh. - case "$sh" in - '') sh="$tmp_sh" ;; - esac - hint=previous - ;; - esac -fi -if test ! -f config.sh; then - $cat <&4 - dflt='' - : Half the following guesses are probably wrong... If you have better - : tests or hints, please send them to - : The metaconfig authors would also appreciate a copy... - $test -f /irix && osname=irix - $test -f /xenix && osname=sco_xenix - $test -f /dynix && osname=dynix - $test -f /dnix && osname=dnix - $test -f /lynx.os && osname=lynxos - $test -f /unicos && osname=unicos && osvers=`$uname -r` - $test -f /unicosmk.ar && osname=unicosmk && osvers=`$uname -r` - $test -f /bin/mips && /bin/mips && osname=mips - $test -d /NextApps && set X `hostinfo | grep 'NeXT Mach.*:' | \ - $sed -e 's/://' -e 's/\./_/'` && osname=next && osvers=$4 - $test -d /usr/apollo/bin && osname=apollo - $test -f /etc/saf/_sactab && osname=svr4 - $test -d /usr/include/minix && osname=minix - if $test -d /MachTen; then -?X: MachTen uname -a output looks like -?X: xxx 4 0.0 Macintosh -?X: MachTen /sbin/version output looks like -?X: MachTen 4.0 Mon Aug 28 10:18:00 1995 -?X: MachTen 3.x had the 'version' command in /usr/etc/version. - osname=machten - if $test -x /sbin/version; then - osvers=`/sbin/version | $awk '{print $2}' | - $sed -e 's/[A-Za-z]$//'` - elif $test -x /usr/etc/version; then - osvers=`/usr/etc/version | $awk '{print $2}' | - $sed -e 's/[A-Za-z]$//'` - else - osvers="$2.$3" - fi - fi -?X: If we have uname, we already computed a suitable uname -a output, correctly -?X: formatted for Xenix, and it lies in $myuname. - if $test -f $uname; then - set X $myuname - shift - - case "$5" in - fps*) osname=fps ;; - mips*) - case "$4" in - umips) osname=umips ;; - *) osname=mips ;; - esac;; - [23]100) osname=mips ;; - next*) osname=next ;; - news*) osname=news ;; -?X: Interactive Unix. - i386*) - if $test -f /etc/kconfig; then - osname=isc - if test "$lns" = "ln -s"; then - osvers=4 - elif $contains _SYSV3 /usr/include/stdio.h > /dev/null 2>&1 ; then - osvers=3 - elif $contains _POSIX_SOURCE /usr/include/stdio.h > /dev/null 2>&1 ; then - osvers=2 - fi - fi - ;; - esac - - case "$1" in - aix) osname=aix -?X: aix 4.1 uname -a output looks like -?X: AIX foo 1 4 000123456789 -?X: where $4 is the major release number and $3 is the (minor) version. -?X: More detail on the version is available with the oslevel command. -?X: in 3.2.x, it output a string (see case statements below). In 4.1, -?X: it puts out something like 4.1.1.0 - tmp=`( (oslevel) 2>/dev/null || echo "not found") 2>&1` - case "$tmp" in - 'not found') osvers="$4"."$3" ;; - '<3240'|'<>3240') osvers=3.2.0 ;; - '=3240'|'>3240'|'<3250'|'<>3250') osvers=3.2.4 ;; - '=3250'|'>3250') osvers=3.2.5 ;; - *) osvers=$tmp;; - esac - ;; - *dc.osx) osname=dcosx - osvers="$3" - ;; - dnix) osname=dnix - osvers="$3" - ;; - domainos) osname=apollo - osvers="$3" - ;; - dgux) osname=dgux - osvers="$3" - ;; -?X: uname -a returns -?X: DYNIX/ptx xxx 4.0 V4.1.2 i386 - dynixptx*) osname=dynixptx - osvers="$3" - ;; - freebsd) osname=freebsd - osvers="$3" ;; - genix) osname=genix ;; - hp*) osname=hpux - case "$3" in - *.08.*) osvers=9 ;; - *.09.*) osvers=9 ;; - *.10.*) osvers=10 ;; - *) osvers="$3" ;; - esac - ;; - irix*) osname=irix - case "$3" in - 4*) osvers=4 ;; - 5*) osvers=5 ;; - 6*) osvers=6 ;; - *) osvers="$3" ;; - esac - ;; - linux) osname=linux - case "$3" in - 1*) osvers=1 ;; - *) osvers="$3" ;; - esac - ;; - netbsd*) osname=netbsd - osvers="$3" - ;; - bsd386) osname=bsd386 - osvers=`$uname -r` - ;; - next*) osname=next ;; - solaris) osname=solaris - case "$3" in - 5*) osvers=`echo $3 | $sed 's/^5/2/g'` ;; - *) osvers="$3" ;; - esac - ;; - sunos) osname=sunos - case "$3" in - 5*) osname=solaris - osvers=`echo $3 | $sed 's/^5/2/g'` ;; - *) osvers="$3" ;; - esac - ;; - titanos) osname=titanos - case "$3" in - 1*) osvers=1 ;; - 2*) osvers=2 ;; - 3*) osvers=3 ;; - 4*) osvers=4 ;; - *) osvers="$3" ;; - esac - ;; - ultrix) osname=ultrix - osvers="$3" - ;; - osf1|mls+) case "$5" in - alpha) -?X: DEC OSF/1 myuname -a output looks like: osf1 xxxx t3.2 123.4 alpha -?X: where the version number can be either vn.n or tn.n. - osname=dec_osf - osvers=`echo "$3" | sed 's/^[vt]//'` - ;; - hp*) osname=hp_osf1 ;; - mips) osname=mips_osf1 ;; -?X: hp and mips were unsupported Technology Releases -- ADO, 24/10/94 - esac - ;; - uts) osname=uts - osvers="$3" - ;; - qnx) osname=qnx - osvers="$4" - ;; - mingw32*) osname=mingw32 - osvers="$3" - ;; - $2) case "$osname" in - *isc*) ;; - *freebsd*) ;; - svr*) - : svr4.x or possibly later - case "svr$3" in - ${osname}*) - osname=svr$3 - osvers=$4 - ;; - esac - case "$osname" in - svr4.0) - : Check for ESIX - if test -f /stand/boot ; then - eval `grep '^INITPROG=[a-z/0-9]*$' /stand/boot` - if test -n "$INITPROG" -a -f "$INITPROG"; then - isesix=`strings -a $INITPROG|grep 'ESIX SYSTEM V/386 Release 4.0'` - if test -n "$isesix"; then - osname=esix4 - fi - fi - fi - ;; - esac - ;; - *) if test -f /etc/systemid; then - osname=sco - set `echo $3 | $sed 's/\./ /g'` $4 - if $test -f sco_$1_$2_$3.sh; then - osvers=$1.$2.$3 - elif $test -f sco_$1_$2.sh; then - osvers=$1.$2 - elif $test -f sco_$1.sh; then - osvers=$1 - fi - else - case "$osname" in - '') : Still unknown. Probably a generic Sys V. - osname="sysv" - osvers="$3" - ;; - esac - fi - ;; - esac - ;; - *) case "$osname" in - '') : Still unknown. Probably a generic BSD. - osname="$1" - osvers="$3" - ;; - esac - ;; - esac - else -?X: Try to identify sony's NEWS-OS (BSD unix) - if test -f /vmunix -a -f $src/hints/news_os.sh; then - (what /vmunix | UU/tr '[A-Z]' '[a-z]') > UU/kernel.what 2>&1 - if $contains news-os UU/kernel.what >/dev/null 2>&1; then - osname=news_os - fi - $rm -f UU/kernel.what -?X: Maybe it's an OS/2 -?X: Might also be win32 - elif test -d c:/.; then - : Check for cygwin32 emulation - case "x$OS" in - xWindows_*) - set X $myuname - osname=win32 - osvers="$3" - ;; - x*) - set X $myuname - osname=os2 - osvers="$5" - ;; - esac - fi - fi -?X: Fix up cygwin32 to win32, just because... - case "x$osname" in - xcygwin32*) - osname=win32 - ;; - esac - - : Now look for a hint file osname_osvers, unless one has been - : specified already. - case "$hintfile" in - ''|' ') - file=`echo "${osname}_${osvers}" | $sed -e 's@\.@_@g' -e 's@_$@@'` - : Also try without trailing minor version numbers. - xfile=`echo $file | $sed -e 's@_[^_]*$@@'` - xxfile=`echo $xfile | $sed -e 's@_[^_]*$@@'` - xxxfile=`echo $xxfile | $sed -e 's@_[^_]*$@@'` - xxxxfile=`echo $xxxfile | $sed -e 's@_[^_]*$@@'` - case "$file" in - '') dflt=none ;; - *) case "$osvers" in - '') dflt=$file - ;; - *) if $test -f $src/hints/$file.sh ; then - dflt=$file - elif $test -f $src/hints/$xfile.sh ; then - dflt=$xfile - elif $test -f $src/hints/$xxfile.sh ; then - dflt=$xxfile - elif $test -f $src/hints/$xxxfile.sh ; then - dflt=$xxxfile - elif $test -f $src/hints/$xxxxfile.sh ; then - dflt=$xxxxfile - elif $test -f "$src/hints/${osname}.sh" ; then - dflt="${osname}" - else - dflt=none - fi - ;; - esac - ;; - esac - ;; - *) - dflt=`echo $hintfile | $sed 's/\.sh$//'` - ;; - esac - - $cat <> UU/config.sh - elif $test X$tans = X -o X$tans = Xnone ; then - : nothing - else - : Give one chance to correct a possible typo. - echo "$file.sh does not exist" - dflt=$file - rp="hint to use instead?" - . UU/myread - for file in $ans; do - if $test -f "$src/hints/$file.sh"; then - . $src/hints/$file.sh - $cat $src/hints/$file.sh >> UU/config.sh - elif $test X$ans = X -o X$ans = Xnone ; then - : nothing - else - echo "$file.sh does not exist -- ignored." - fi - done - fi - done - - hint=recommended - : Remember our hint file for later. - if $test -f "$src/hints/$file.sh" ; then - hintfile="$file" - else - hintfile='' - fi -fi -cd UU -?X: From here on, we must use $rsrc instead of $src -@else -: Get old answers, if there is a config file out there -hint=default -hintfile='' -if test -f ../config.sh; then - echo " " - rp="I see a config.sh file. Shall I use it to set the defaults?" - . ./myread - case "$ans" in - n*|N*) echo "OK, I'll ignore it.";; - *) echo "Fetching default answers from your old config.sh file..." >&4 - tmp_n="$n" - tmp_c="$c" - . ../config.sh - cp ../config.sh . - n="$tmp_n" - c="$tmp_c" - hint=previous - ;; - esac -fi -@end -?X: remember, indentation is wrong--RAM -;; -*) - echo " " - echo "Fetching default answers from $config_sh..." >&4 - tmp_n="$n" - tmp_c="$c" - cd .. -?X: preserve symbolic links, if any - cp $config_sh config.sh 2>/dev/null - chmod +w config.sh - . ./config.sh - cd UU - cp ../config.sh . - n="$tmp_n" - c="$tmp_c" - hint=previous - ;; -esac -test "$override" && . ./optdef.sh -myuname="$newmyuname" - -: Restore computed paths -for file in $loclist $trylist; do - eval $file="\$_$file" -done - -@if osname || osvers -cat << EOM - -Configure uses the operating system name and version to set some defaults. -The default value is probably right if the name rings a bell. Otherwise, -since spelling matters for me, either accept the default or answer "none" -to leave it blank. - -EOM -@end -@if osname -case "$osname" in - ''|' ') - case "$hintfile" in - ''|' '|none) dflt=none ;; - *) dflt=`echo $hintfile | $sed -e 's/\.sh$//' -e 's/_.*$//'` ;; - esac - ;; - *) dflt="$osname" ;; -esac -rp="Operating system name?" -. ./myread -case "$ans" in -none) osname='' ;; -*) osname=`echo "$ans" | $sed -e 's/[ ][ ]*/_/g' | ./tr '[A-Z]' '[a-z]'`;; -esac -@end -@if osvers -@if osname -echo " " -@end -case "$osvers" in - ''|' ') - case "$hintfile" in - ''|' '|none) dflt=none ;; - *) dflt=`echo $hintfile | $sed -e 's/\.sh$//' -e 's/^[^_]*//'` - dflt=`echo $dflt | $sed -e 's/^_//' -e 's/_/./g'` - case "$dflt" in - ''|' ') dflt=none ;; - esac - ;; - esac - ;; - *) dflt="$osvers" ;; -esac -rp="Operating system version?" -. ./myread -case "$ans" in -none) osvers='' ;; -*) osvers="$ans" ;; -esac - -@end diff --git a/U/ccflags.U b/U/ccflags.U deleted file mode 100644 index 66bc158..0000000 --- a/U/ccflags.U +++ /dev/null @@ -1,426 +0,0 @@ -?RCS: $Id: ccflags.U 1.6 Sat, 24 Jan 2004 13:13:31 -0600 dunemush $ -?RCS: -?RCS: Copyright (c) 1991-1993, Raphael Manfredi -?RCS: -?RCS: You may redistribute only under the terms of the Artistic Licence, -?RCS: as specified in the README file that comes with the distribution. -?RCS: You may reuse parts of this distribution only within the terms of -?RCS: that same Artistic Licence; a copy of which may be found at the root -?RCS: of the source tree for dist 3.0. -?RCS: -?RCS: $Log: ccflags.U,v $ -?RCS: Revision 3.0.1.9 1997/02/28 15:27:07 ram -?RCS: patch61: removed support for NO_PROTOTYPE detection on SCO -?RCS: patch61: new locincpth variable -?RCS: patch61: added info on the "additional ld flags" question -?RCS: -?RCS: Revision 3.0.1.8 1995/07/25 13:48:54 ram -?RCS: patch56: re-arranged compile line to include ldflags before objects -?RCS: -?RCS: Revision 3.0.1.7 1995/05/12 12:08:33 ram -?RCS: patch54: now checks for cc/ccflags/ldflags coherency -?RCS: -?RCS: Revision 3.0.1.6 1994/10/29 16:07:02 ram -?RCS: patch36: gcc versionning no longer relies on the C compiler's name -?RCS: patch36: simplified check for gcc version checking (ADO) -?RCS: -?RCS: Revision 3.0.1.5 1994/08/29 16:06:35 ram -?RCS: patch32: propagate -posix flag from ccflags to ldflags -?RCS: -?RCS: Revision 3.0.1.4 1994/05/06 14:28:45 ram -?RCS: patch23: -fpcc-struct-return only needed in gcc 1.x (ADO) -?RCS: patch23: cppflags now computed on an option-by-option basis -?RCS: patch23: magically added cc flags now only done the first time -?RCS: -?RCS: Revision 3.0.1.3 1993/09/13 15:58:29 ram -?RCS: patch10: explicitely mention -DDEBUG just in case they need it (WAD) -?RCS: patch10: removed all the "tans" variable usage (WAD) -?RCS: -?RCS: Revision 3.0.1.2 1993/08/27 14:39:38 ram -?RCS: patch7: added support for OSF/1 machines -?RCS: -?RCS: Revision 3.0.1.1 1993/08/25 14:00:24 ram -?RCS: patch6: added defaults for cppflags, ccflags and ldflags -?RCS: -?RCS: Revision 3.0 1993/08/18 12:05:31 ram -?RCS: Baseline for dist 3.0 netwide release. -?RCS: -?MAKE:ccflags ldflags lkflags cppflags optimize warnings locincpth: test cat \ - Myread Guess Options Oldconfig +gccversion mips_type +usrinc \ - package contains rm +cc cppstdin cppminus cpprun cpplast libpth \ - loclibpth hint -?MAKE: -pick add $@ %< -?S:ccflags: -?S: This variable contains any additional C compiler flags desired by -?S: the user. It is up to the Makefile to use this. -?S:. -?S:cppflags: -?S: This variable holds the flags that will be passed to the C pre- -?S: processor. It is up to the Makefile to use it. -?S:. -?S:optimize: -?S: This variable contains any optimizer/debugger flag that should be used. -?S: It is up to the Makefile to use it. -?S:. -?S:warnings: -?S: This variable contains any compiler warning flags that should be used. -?S:. -?S:ldflags: -?S: This variable contains any additional C loader flags desired by -?S: the user. It is up to the Makefile to use this. -?S:. -?S:lkflags: -?S: This variable contains any additional C partial linker flags desired by -?S: the user. It is up to the Makefile to use this. -?S:. -?S:locincpth: -?S: This variable contains a list of additional directories to be -?S: searched by the compiler. The appropriate -I directives will -?S: be added to ccflags. This is intended to simplify setting -?S: local directories from the Configure command line. -?S: It's not much, but it parallels the loclibpth stuff in libpth.U. -?S:. -?T:inctest thisincl xxx flag inclwanted ftry previous thislibdir -?D:cppflags='' -?D:ccflags='' -?D:ldflags='' -?D:optimize='' -?D:warnings='' -?INIT:: Possible local include directories to search. -?INIT:: Set locincpth to "" in a hint file to defeat local include searches. -?INIT:locincpth="/usr/local/include /opt/local/include /usr/gnu/include" -?INIT:locincpth="$locincpth /opt/gnu/include /usr/GNU/include /opt/GNU/include" -?INIT:locincpth="$locincpth /usr/kerberos/include" -?INIT:: -?INIT:: no include file wanted by default -?INIT:inclwanted='' -?INIT: -: determine optimize, if desired, or use for debug flag also -case "$optimize" in -' ') dflt='none';; -'') case $gccversion in - 2*) dflt='-g -O' ;; - *egcs*) dflt='-g -O' ;; - *) dflt='-g' ;; - esac ;; -*) dflt="$optimize";; -esac -$cat </dev/null 2>&1 - then - dflt="$dflt -posix" - fi - ;; - esac - ;; -esac - -?X: In USG mode, a MIPS system may need some BSD includes -case "$mips_type" in -*BSD*|'') inclwanted="$locincpth $usrinc";; -*) inclwanted="$locincpth $inclwanted $usrinc/bsd";; -esac -for thisincl in $inclwanted; do - if $test -d $thisincl; then - if $test x$thisincl != x$usrinc; then - case "$dflt" in - *$thisincl*);; - *) dflt="$dflt -I$thisincl";; - esac - fi - fi -done - -?X: Include test function (header, symbol) -inctest='if $contains $2 $usrinc/$1 >/dev/null 2>&1; then - xxx=true; -elif $contains $2 $usrinc/sys/$1 >/dev/null 2>&1; then - xxx=true; -else - xxx=false; -fi; -if $xxx; then - case "$dflt" in - *$2*);; - *) dflt="$dflt -D$2";; - esac; -fi' - -?X: -?X: OSF/1 uses __LANGUAGE_C__ instead of LANGUAGE_C -?X: -if ./osf1; then - set signal.h __LANGUAGE_C__; eval $inctest -else - set signal.h LANGUAGE_C; eval $inctest -fi - -case "$hint" in -none|recommended) dflt="$ccflags $dflt" ;; -*) dflt="$ccflags";; -esac - -case "$dflt" in -''|' ') dflt=none;; -esac -$cat <&4 - set X $cppflags - shift - cppflags='' - $cat >cpp.c <<'EOM' -#define BLURFL foo - -BLURFL xx LFRULB -EOM -?X: -?X: For each cc flag, try it out with both cppstdin and cpprun, since the -?X: first is almost surely a cc wrapper. We have to try both in case -?X: of cc flags like '-Olimit 2900' that are actually two words... -?X: - previous='' - for flag in $* - do - case "$flag" in - -*) ftry="$flag";; - *) ftry="$previous $flag";; - esac - if $cppstdin -DLFRULB=bar $ftry $cppminus cpp1.out 2>/dev/null && \ - $cpprun -DLFRULB=bar $ftry $cpplast cpp2.out 2>/dev/null && \ - $contains 'foo.*xx.*bar' cpp1.out >/dev/null 2>&1 && \ - $contains 'foo.*xx.*bar' cpp2.out >/dev/null 2>&1 - then - cppflags="$cppflags $ftry" - previous='' - else - previous="$flag" - fi - done - set X $cppflags - shift - cppflags=${1+"$@"} - case "$cppflags" in - *-*) echo "They appear to be: $cppflags";; - esac - $rm -f cpp.c cpp?.out - ;; -esac - -: flags used in final linking phase -case "$ldflags" in -'') if ./venix; then - dflt='-i -z' - else - dflt='' - fi - case "$ccflags" in - *-posix*) dflt="$dflt -posix" ;; - esac - ;; -*) dflt="$ldflags";; -esac - -: Try to guess additional flags to pick up local libraries. -for thislibdir in $libpth; do - case " $loclibpth " in - *" $thislibdir "*) - case "$dflt " in - *"-L$thislibdir "*) ;; - *) dflt="$dflt -L$thislibdir" ;; - esac - ;; - esac -done - -case "$dflt" in -'') dflt='none' ;; -esac - -$cat <&4 -?X: Strip extra blanks in case some of the following variables are empty -set X $cc $optimize $ccflags $ldflags try.c -o try -shift -$cat >try.msg < try.c <<'EOF' -#include -main() { exit(0); } -EOF -dflt=y -?X: Use "sh -c" to avoid error messages tagged with leading "Configure:". -?X: We need to try the resulting executable, because cc might yield a 0 status -?X: even when ld failed, in which case the executable will not run properly, -?X: if its x bit is set at all... -if sh -c "$cc $optimize $ccflags try.c -o try $ldflags" >>try.msg 2>&1; then - if sh -c './try' >>try.msg 2>&1; then - dflt=n - else - echo "The program compiled OK, but exited with status $?." >>try.msg - rp="You have a problem. Shall I abort Configure" - dflt=y - fi -else - echo "I can't compile the test program." >>try.msg - rp="You have a BIG problem. Shall I abort Configure" - dflt=y -fi -case "$dflt" in -y) - $cat try.msg -?X: using -K will prevent default aborting--maybe they're cross compiling? - case "$knowitall" in - '') - echo "(The supplied flags might be incorrect with this C compiler.)" - ;; - *) dflt=n;; - esac - echo " " - . ./myread - case "$ans" in - n*|N*) ;; - *) echo "Ok. Stopping Configure." >&4 - exit 1 - ;; - esac - ;; -n) echo "OK, that should do.";; -esac -$rm -f try try.* core - diff --git a/U/cdecl.U b/U/cdecl.U deleted file mode 100644 index 59e9ae7..0000000 --- a/U/cdecl.U +++ /dev/null @@ -1,48 +0,0 @@ -?RCS: $Id: cdecl.U 1.3 Wed, 17 Mar 2004 16:02:04 -0600 dunemush $ -?RCS: -?RCS: Copyright (c) 1995, Alan Schwartz -?RCS: -?RCS: You may redistribute only under the terms of the Artistic Licence, -?RCS: as specified in the README file that comes with the distribution. -?RCS: You may reuse parts of this distribution only within the terms of -?RCS: that same Artistic Licence; a copy of which may be found at the root -?RCS: of the source tree for dist 3.0. -?RCS: -?MAKE:cdecl: Myread cat cc ccflags rm -?MAKE: -pick add $@ %< -?S:cdecl: -?S: Defined to be __cdecl if the compiler can handle a __cdecl keyword -?S: to specify C-style argument passing conventions. Otherwise defined -?S: as nothing. Basically MS VC++. -?S:. -?C:WIN32_CDECL: -?C: Defined as __cdecl if the compiler can handle that keyword to specify -?C: C-style argument passing conventions. This allows MS VC++ -?C: on Win32 to use the __fastcall convention for everything else -?C: and get a performance boost. Any compiler with a brain (read: -?C: not MS VC) handles this optimization automatically without such a -?C: kludge. On these systems, this is defined as nothing. -?C:. -?H:#define WIN32_CDECL $cdecl -?H:. -: check for a __cdecl use -echo " " -$cat >test_cdecl.c <<'EOCP' -#include -#include -#define WIN32_CDECL __cdecl - -int WIN32_CDCEL main(int argc, char **argv) { - exit(0); -} -EOCP - -if ($cc $ccflags -o test_cdecl test_cdecl.c && ./test_cdecl) >/dev/null 2>&1 ; then - cdecl='__cdecl' - echo 'Your compiler likes __cdecl as a keyword.' >&4 -else - cdecl='' - echo "Your compiler doesn't grok __cdecl - it probably has a brain." >&4 -fi -$rm -f test_cdecl* core - diff --git a/U/cf_name.U b/U/cf_name.U deleted file mode 100644 index ffdd79c..0000000 --- a/U/cf_name.U +++ /dev/null @@ -1,72 +0,0 @@ -?RCS: $Id$ -?RCS: -?RCS: Copyright (c) 1991-1993, Raphael Manfredi -?RCS: -?RCS: You may redistribute only under the terms of the Artistic Licence, -?RCS: as specified in the README file that comes with the distribution. -?RCS: You may reuse parts of this distribution only within the terms of -?RCS: that same Artistic Licence; a copy of which may be found at the root -?RCS: of the source tree for dist 3.0. -?RCS: -?RCS: Original Author: Graham Stoney -?RCS: -?RCS: $Log: cf_name.U,v $ -?RCS: Revision 3.0.1.2 1994/05/06 14:29:36 ram -?RCS: patch23: fixed user name computation from /etc/passwd in bsd systems -?RCS: -?RCS: Revision 3.0.1.1 1994/01/24 14:05:11 ram -?RCS: patch16: created -?RCS: -?RCS: -?MAKE:cf_name: cf_by passcat Filexp nametype cat test -?MAKE: -pick add $@ %< -?S:cf_name: -?S: Full name of the person who ran the Configure script and answered the -?S: questions. This can be used by units that require the user's full name. -?S: This variable is for internal use only. -?S:. -?T:xxx fn NAME -: figure out their full name -case "$NAME" in -'') case "$nametype" in - other) - fn=`./filexp ~/.fullname` - xxx=usg - $test -f $fn && xxx=other - ;; - *) - xxx="$nametype" - ;; - esac - - case "$xxx" in - bsd) - cf_name=`$passcat | grep "^$cf_by:" | \ - sed -e 's/^[^:]*:[^:]*:[^:]*:[^:]*:\([^:]*\):.*/\1/' \ - -e 's/,.*//'` - ;; - usg) - cf_name=`$passcat | grep "^$cf_by:" | \ - sed -e 's/^[^:]*:[^:]*:[^:]*:[^:]*:\([^:]*\):.*/\1/' \ - -e 's/[^-]*-\(.*\)(.*)/\1/'` - ;; - *) - cf_name=`$cat $fn` - ;; - esac - ;; -*) - cf_name="$NAME" - ;; -esac -?X: -?X: In the original unit, Graham asked for the user name, in case the above -?X: code was unable to figure it out correctly. Since now cf_name has been -?X: made an internal variable only (i.e. it is not saved in config.sh), letting -?X: the user override the computed default each time would be a pain. -?X: Therefore, I have decided to trust the above code to get it right, and for -?X: those rare cases where it will fail, too bad :-) --RAM. -?X: -echo " " -echo "Pleased to meet you, $cf_name." - diff --git a/U/d_argsinfp.U b/U/d_argsinfp.U deleted file mode 100644 index d4ab973..0000000 --- a/U/d_argsinfp.U +++ /dev/null @@ -1,46 +0,0 @@ -?RCS: $Id: d_argsinfp.U 1.1 Thu, 20 Jul 2000 17:42:54 -0500 dunemush $ -?RCS: -?RCS: Copyright (c) 1995, Alan Schwartz -?RCS: -?RCS: You may redistribute only under the terms of the Artistic Licence, -?RCS: as specified in the README file that comes with the distribution. -?RCS: You may reuse parts of this distribution only within the terms of -?RCS: that same Artistic Licence; a copy of which may be found at the root -?RCS: of the source tree for dist 3.0. -?RCS: -?MAKE:d_argsinfp: Myread cat cc ccflags rm ldflags -?MAKE: -pick add $@ %< -?S:d_argsinfp: -?S: Defined if new-style function definitions are allowable. -?S:. -?C:CAN_TAKE_ARGS_IN_FP: -?C: Defined if the compiler prefers that function pointer parameters -?C: in prototypes include the function's arguments, rather than -?C: nothing (that is, int (*fun)(int) rather than int(*fun)(). -?C:. -?H:#$d_argsinfp CAN_TAKE_ARGS_IN_FP /**/ -?H:. -: check for ok to use function ptr arguments in prototypes -echo " " -$cat >test_argsinfp.c <<'EOCP' -#include -int myfun(int); -int fun(int (*func)(int)); -int fun2(int, int (*prevfun)(int(*func)(int))); -int fun (int (*func)(int)) { int a = 1; return func(a); } -int myfun(int x) { return x - 1; } - -int main(int argc, char **argv) { - exit(fun(myfun)); -} -EOCP - -if $cc $ccflags $ldflags -o test_argsinfp test_argsinfp.c >/dev/null 2>&1 ; then - d_argsinfp='define' - echo 'Your compiler prefers arguments in function pointers in prototypes.' >&4 -else - d_argsinfp='undef' - echo "Your compiler prefers no arguments in function pointers in prototypes." >&4 -fi -$rm -f test_argsinfp* core - diff --git a/U/d_assert.U b/U/d_assert.U deleted file mode 100644 index 2e2c468..0000000 --- a/U/d_assert.U +++ /dev/null @@ -1,41 +0,0 @@ -?RCS: $Id: d_assert.U 1.1 Thu, 20 Jul 2000 17:42:54 -0500 dunemush $ -?RCS: -?RCS: Revision 3.0 1993/08/18 12:05:39 ram -?RCS: Baseline for dist 3.0 netwide release. -?RCS: -?MAKE:d_assert: Myread cat cc ccflags rm Setvar libs ldflags -?MAKE: -pick add $@ %< -?S:d_assert: -?S: This variable is set if the system has the assert() macro -?S:. -?C:HAS_ASSERT: -?C: If defined, this system has the assert() macro. -?C:. -?H:#$d_assert HAS_ASSERT /**/ -?H:. -?T:val -?LINT:set d_assert -: see if we have the assert macro -echo " " -echo "Let's see if I can assert() myself." >&4 - $cat >d_assert.c < -#include - -int main() -{ - assert(1); -} -EOCP - -if $cc $ccflags $ldflags d_assert.c -o d_assert $libs >/dev/null 2>&1; then - val="$define" - set d_assert; eval $setvar - echo "Looks like I can." >&4 -else - val="$undef" - set d_assert; eval $setvar - echo "Nope, I need assertiveness training." >&4 -fi -$rm -f d_assert* - diff --git a/U/d_attribut.U b/U/d_attribut.U deleted file mode 100644 index 0c127ac..0000000 --- a/U/d_attribut.U +++ /dev/null @@ -1,64 +0,0 @@ -?RCS: $Id: d_attribut.U 1.1 Thu, 20 Jul 2000 17:42:54 -0500 dunemush $ -?RCS: -?RCS: Copyright (c) 1991-1993, Raphael Manfredi -?RCS: -?RCS: You may redistribute only under the terms of the Artistic Licence, -?RCS: as specified in the README file that comes with the distribution. -?RCS: You may reuse parts of this distribution only within the terms of -?RCS: that same Artistic Licence; a copy of which may be found at the root -?RCS: of the source tree for dist 3.0. -?RCS: -?RCS: Original Author: Andy Dougherty -?RCS: -?RCS: $Log: d_attribut.U,v $ -?RCS: Revision 3.0.1.3 1995/01/30 14:33:45 ram -?RCS: patch49: test C program now includes (WED) -?RCS: -?RCS: Revision 3.0.1.2 1995/01/11 15:25:47 ram -?RCS: patch45: fixed typo in the d_attribut variable (ADO) -?RCS: -?RCS: Revision 3.0.1.1 1994/10/29 16:08:55 ram -?RCS: patch36: created by ADO -?RCS: -?MAKE:d_attribut: Myread Oldconfig cat cc ccflags rm Setvar contains optimize -?MAKE: -pick add $@ %< -?S:d_attribut (d_attrib): -?S: This variable conditionally defines HASATTRIBUTE, which -?S: indicates the C compiler can check for function attributes, -?S: such as printf formats. -?S:. -?C:HASATTRIBUTE ~ %< (GNUC_ATTRIBUTE_CHECK): -?C: This symbol indicates the C compiler can check for function attributes, -?C: such as printf formats. This is normally only supported by GNU cc. -?C:. -?H:?%<:#$d_attribut HASATTRIBUTE /**/ -?H:?%<:#ifndef HASATTRIBUTE -?H:?%<:#define __attribute__(_arg_) -?H:?%<:#endif -?H:. -?W:%<:__attribute__ -?LINT:set d_attribut -?LINT:known __attribute__ -: Look for GNU-cc style attribute checking -echo " " -echo "Checking whether your compiler can handle __attribute__ ..." >&4 -$cat >attrib.c <<'EOCP' -#include -void croak (char* pat,...) __attribute__((format(printf,1,2),noreturn)); -EOCP -if $cc $optimize $ccflags -c attrib.c >attrib.out 2>&1 ; then - if $contains 'warning' attrib.out >/dev/null 2>&1; then - echo "Your C compiler doesn't fully support __attribute__." - val="$undef" - else - echo "Your C compiler supports __attribute__." - val="$define" - fi -else - echo "Your C compiler doesn't seem to understand __attribute__ at all." - val="$undef" -fi -set d_attribut -eval $setvar -$rm -f attrib* - diff --git a/U/d_bindtextdomain.U b/U/d_bindtextdomain.U deleted file mode 100644 index dcdf217..0000000 --- a/U/d_bindtextdomain.U +++ /dev/null @@ -1,41 +0,0 @@ -?RCS: $Id: d_bindtextdomain.U 1.2 Wed, 13 Sep 2000 14:49:45 -0500 dunemush $ -?RCS: -?RCS: Copyright (c) 1995, Alan Schwartz -?RCS: -?RCS: You may redistribute only under the terms of the Artistic Licence, -?RCS: as specified in the README file that comes with the distribution. -?RCS: You may reuse parts of this distribution only within the terms of -?RCS: that same Artistic Licence; a copy of which may be found at the root -?RCS: of the source tree for dist 3.0. -?RCS: -?MAKE:d_bindtextdomain: Myread cat cc ccflags rm ldflags libs i_libintl -?MAKE: -pick add $@ %< -?S:d_bindtextdomain: -?S: Defined if bindtextdomain() is available. -?S:. -?C:HAS_BINDTEXTDOMAIN: -?C: Defined if bindtextdomain is available(). -?C:. -?H:#$d_bindtextdomain HAS_BINDTEXTDOMAIN /**/ -?H:. -: check for a new-style definitions -echo " " -$cat >test_bindtextdomain.c < -#endif -int main(int argc, char **argv) { - return (int) bindtextdomain ("", ""); -} -EOCP - -if $cc $ccflags $ldflags -o test_bindtextdomain test_bindtextdomain.c $libs >/dev/null 2>&1 ; then - d_bindtextdomain='define' - echo 'Otima! You seem to have bindtextdomain for translations.' >&4 -else - d_bindtextdomain='undef' - echo "You don't seem to have bindtextdomain. Sinto muito." >&4 -fi -$rm -f test_bindtextdomain* core - diff --git a/U/d_crypt.U b/U/d_crypt.U deleted file mode 100644 index cd5b936..0000000 --- a/U/d_crypt.U +++ /dev/null @@ -1,87 +0,0 @@ -?RCS: $Id: d_crypt.U 1.1 Thu, 20 Jul 2000 17:42:54 -0500 dunemush $ -?RCS: -?RCS: Copyright (c) 1991-1993, Raphael Manfredi -?RCS: -?RCS: You may redistribute only under the terms of the Artistic Licence, -?RCS: as specified in the README file that comes with the distribution. -?RCS: You may reuse parts of this distribution only within the terms of -?RCS: that same Artistic Licence; a copy of which may be found at the root -?RCS: of the source tree for dist 3.0. -?RCS: -?RCS: $Log: d_crypt.U,v $ -?RCS: Revision 3.0 1993/08/18 12:05:52 ram -?RCS: Baseline for dist 3.0 netwide release. -?RCS: -?MAKE:d_crypt cryptlib i_crypt: Loc test xlibpth libpth Csym Setvar Inhdr -?MAKE: -pick add $@ %< -?S:d_crypt: -?S: This variable conditionally defines the CRYPT symbol, which -?S: indicates to the C program that the crypt() routine is available -?S: to encrypt passwords and the like. -?S:. -?S:cryptlib: -?S: This variable holds -lcrypt or the path to a libcrypt.a archive if -?S: the crypt() function is not defined in the standard C library. It is -?S: up to the Makefile to use this. -?S:. -?S:i_crypt: -?S: This variable conditionally defines the I_CRYPT symbol, which -?S: indicates whether a C program should include -?S:. -?C:HAS_CRYPT (CRYPT): -?C: This symbol, if defined, indicates that the crypt routine is available -?C: to encrypt passwords and the like. -?C:. -?C:I_CRYPT: -?C: This symbol, if defined, indicates that can be included. -?C:. -?H:#$d_crypt HAS_CRYPT /**/ -?H:. -?H:#$i_crypt I_CRYPT /**/ -?H:. -?M:crypt: HAS_CRYPT -?M:/* If your system doesn't have the crypt(3) DES encryption code, -?M: * (which isn't exportable from the U.S.), then don't encrypt -?M: */ -?M:#ifndef HAS_CRYPT -?M:#define crypt(s,t) (s) -?M:#endif -?M:. -?LINT:set d_crypt i_crypt -?T:val -: see if crypt exists -echo " " -if set crypt val -f d_crypt; eval $csym; $val; then - echo 'crypt() found.' >&4 - val="$define" - cryptlib='' -else - cryptlib=`./loc Slibcrypt.a "" $xlibpth` - if $test -z "$cryptlib"; then - cryptlib=`./loc Mlibcrypt.a "" $xlibpth` - else - cryptlib=-lcrypt - fi - if $test -z "$cryptlib"; then - cryptlib=`./loc Llibcrypt.a "" $xlibpth` - else - cryptlib=-lcrypt - fi - if $test -z "$cryptlib"; then - cryptlib=`./loc libcrypt.a "" $libpth` - else - cryptlib=-lcrypt - fi - if $test -z "$cryptlib"; then - echo 'crypt() NOT found!' >&4 - val="$undef" - else - val="$define" - fi -fi -set d_crypt -eval $setvar -: see if crypt.h can be included -set crypt.h i_crypt -eval $inhdr - diff --git a/U/d_force_ipv4.U b/U/d_force_ipv4.U deleted file mode 100644 index f17197d..0000000 --- a/U/d_force_ipv4.U +++ /dev/null @@ -1,21 +0,0 @@ -?RCS: $Id: d_force_ipv4.U 1.1 Sat, 17 Mar 2001 14:16:55 -0600 dunemush $ -?RCS: -?RCS: Revision 3.0 1993/08/18 12:05:39 ram -?RCS: Baseline for dist 3.0 netwide release. -?RCS: -?MAKE:d_force_ipv4: Myread cat cc ccflags rm Setvar libs ldflags -?MAKE: -pick add $@ %< -?S:d_force_ipv4: -?S: This variable allows us to force the use of ipv4 rather than ipv6. -?S:. -?C:FORCE_IPV4: -?C: If defined, this system will not use IPv6. Necessary for Openbsd. -?C:. -?H:#$d_force_ipv4 FORCE_IPV4 /**/ -?H:. -?T:val -?LINT:set d_force_ipv4 -: Do nothing by default -val="$undef" -set d_force_ipv4; eval $setvar - diff --git a/U/d_fpsetround.U b/U/d_fpsetround.U deleted file mode 100644 index 6216823..0000000 --- a/U/d_fpsetround.U +++ /dev/null @@ -1,93 +0,0 @@ -?RCS: $Id: d_fpsetround.U 1.2 Wed, 17 Mar 2004 16:02:04 -0600 dunemush $ -?RCS: -?RCS: You may redistribute only under the terms of the Artistic Licence, -?RCS: as specified in the README file that comes with the distribution. -?RCS: You may reuse parts of this distribution only within the terms of -?RCS: that same Artistic Licence; a copy of which may be found at the root -?RCS: of the source tree for dist 3.0. -?RCS: -?RCS: $Log: d_fpsetround.U,v $ -?RCS: -?MAKE:d_fpsetround d_fpsetmask i_floatingpoint: Loc test Csym Setvar Inhdr cc ccflags libs rm cat test ldflags -?MAKE: -pick add $@ %< -?S:d_fpsetround: -?S: This variable conditionally defines the HAS_FPSETROUND symbol, -?S: indicating we have fpsetround(), a FreeBSD thing, mostly. -?S:. -?S:d_fpsetmask: -?S: This variable conditionally defines the HAS_FPSETMASK symbol, -?S: indicating we have fpsetmask(), a FreeBSD thing, mostly. -?S:. -?S:i_floatingpoint: -?S: This variable conditionally defines the I_FLOATINGPOINT symbol, which -?S: indicates whether a C program should include , -?S: a FreeBSD thing, mostly. -?S:. -?C:HAS_FPSETROUND: -?C: This symbol, if defined, indicates that the crypt routine is available -?C: to encrypt passwords and the like. -?C:. -?C:I_FLOATINGPOINT: -?C: This symbol, if defined, indicates that can be included. -?C:. -?H:#$d_fpsetround HAS_FPSETROUND /**/ -?H:. -?H:#$d_fpsetmask HAS_FPSETMASK /**/ -?H:. -?H:#$i_floatingpoint I_FLOATINGPOINT /**/ -?H:. -?LINT:set d_fpsetround d_fpsetmask i_floatingpoint -?T:val -echo " " -: see if floatingpoint.h can be included -set floatingpoint.h i_floatingpoint -eval $inhdr - -: see if fpsetround exists -$cat >test_fpsetround.c <<'EOCP' -#$i_floatingpoint I_FLOATINGPOINT -#ifdef I_FLOATINGPOINT -#include -#endif - -int main() { - fpsetround(FP_RN); -} -EOCP - -if ($cc $ccflags $ldflags -o test_fpsetround test_fpsetround.c $libs \ - && ./test_fpsetround) >/dev/null 2>&1 ; then - echo 'fpsetround() is around (and found).' >&4 - val="$define" -else - echo 'no fpsetround(). No problem.' >&4 - val="$undef" -fi -set d_fpsetround -eval $setvar - -: see if fpsetmask exists -$cat >test_fpsetmask.c <<'EOCP' -#$i_floatingpoint I_FLOATINGPOINT -#ifdef I_FLOATINGPOINT -#include -#endif - -int main() { - fpsetmask(0L); -} -EOCP - -if ($cc $ccflags $ldflags -o test_fpsetmask test_fpsetmask.c $libs && \ - ./test_fpsetmask) >/dev/null 2>&1 ; then - echo 'fpsetmask() is up to the task.' >&4 - val="$define" -else - echo 'no fpsetmask(). No problem.' >&4 - val="$undef" -fi -set d_fpsetmask -eval $setvar - -$rm -f test_fpset* core - diff --git a/U/d_gaistr.U b/U/d_gaistr.U deleted file mode 100644 index 310b18c..0000000 --- a/U/d_gaistr.U +++ /dev/null @@ -1,27 +0,0 @@ -?RCS: -?RCS: Copyright (c) 200, Shawn Wagner -?RCS: -?RCS: You may redistribute only under the terms of the Artistic Licence, -?RCS: as specified in the README file that comes with the distribution. -?RCS: You may reuse parts of this distribution only within the terms of -?RCS: that same Artistic Licence; a copy of which may be found at the root -?RCS: of the source tree for dist 3.0. -?RCS: -?MAKE:d_gaistr: Inlibc -?MAKE: -pick add $@ %< -?S:d_gaistr (d_gaistr): -?S: This variable conditionally defines the HAS_GAI_STRERROR symbol, which -?S: indicates to the C program that getaddrinfo()'s error codes can be -?S: converted to strings for printing. -?S:. -?C:HAS_GAI_STRERROR (GAI_STRERROR): -?C: This symbol, if defined, indicates that getaddrinfo()'s error cores -?C: can be converted to strings for printing. -?C:. -?H:#$d_gaistr HAS_GAI_STRERROR /**/ -?H:. -?LINT:set d_gaistr -: see if gai_strerror exists -set gai_strerror d_gaistr -eval $inlibc - diff --git a/U/d_getadinf.U b/U/d_getadinf.U deleted file mode 100644 index 0786248..0000000 --- a/U/d_getadinf.U +++ /dev/null @@ -1,27 +0,0 @@ -?RCS: -?RCS: Copyright (c) 2000, Shawn Wagner -?RCS: -?RCS: You may redistribute only under the terms of the Artistic Licence, -?RCS: as specified in the README file that comes with the distribution. -?RCS: You may reuse parts of this distribution only within the terms of -?RCS: that same Artistic Licence; a copy of which may be found at the root -?RCS: of the source tree for dist 3.0. -?RCS: -?MAKE:d_getadinf: Inlibc -?MAKE: -pick add $@ %< -?S:d_getadinf (d_getadinf): -?S: This variable conditionally defines the HAS_GETADDRINFO symbol, which -?S: indicates to the C program that the getaddrinfo() routine is available -?S: to lookup internet addresses in one data base or another.. -?S:. -?C:HAS_GETADDRINFO (GETADDRINFO): -?C: This symbol, if defined, indicates that the getaddrinfo() routine is -?C: available to lookup internet addresses in some data base or other. -?C:. -?H:#$d_getadinf HAS_GETADDRINFO /**/ -?H:. -?LINT:set d_getadinf -: see if getaddrinfo exists -set getaddrinfo d_getadinf -eval $inlibc - diff --git a/U/d_getdate.U b/U/d_getdate.U deleted file mode 100644 index cd4dac2..0000000 --- a/U/d_getdate.U +++ /dev/null @@ -1,52 +0,0 @@ -?RCS: $Id: d_getdate.U 1.4 Mon, 04 Dec 2000 10:36:58 -0600 dunemush $ -?RCS: -?RCS: Copyright (c) 2000, Shawn Wagner -?RCS: -?RCS: -?MAKE:d_getdate: Inlibc cc ccflags ldflags libs rm cat i_string -?MAKE: -pick add $@ %< -?S:d_getdate: -?S: This variable conditionally defines the HAS_GETDATE symbol, which -?S: indicates that the getdate() routine exists. The getdate() routine -?S: turns date strings into struct tm's. -?S:. -?C:HAS_GETDATE: -?C: This symbol, if defined, indicates that the getdate() routine is -?C: available to convert date strings into struct tm's. -?C:. -?H:#$d_getdate HAS_GETDATE /**/ -?H:. -?LINT:set d_getdate -: see if getdate exists -set getdate d_getdate -eval $inlibc - -if test $d_getdate = 'define'; then -$cat >test_getdate.c < -#else -#include -#endif -#include -#ifdef __GNUC__ -/* Required to get the getdate() prototype on glibc. */ -#define __USE_XOPEN_EXTENDED -#endif -#include -int main(int argc, char **argv) { - int i; - i = getdate_err; -} -EOCP - -if $cc $ccflags $ldflags -o test_getdate test_getdate.c $libs >/dev/null 2>&1 ; then - d_getdate='define' -else - d_getdate='undef' - echo "You may have getdate, but it's broken." >&4 -fi -$rm -f test_getdate* core - -fi - diff --git a/U/d_gethbynm2.U b/U/d_gethbynm2.U deleted file mode 100644 index 7041852..0000000 --- a/U/d_gethbynm2.U +++ /dev/null @@ -1,27 +0,0 @@ -?RCS: -?RCS: Copyright (c) 2000, Shawn Wagner -?RCS: -?RCS: You may redistribute only under the terms of the Artistic Licence, -?RCS: as specified in the README file that comes with the distribution. -?RCS: You may reuse parts of this distribution only within the terms of -?RCS: that same Artistic Licence; a copy of which may be found at the root -?RCS: of the source tree for dist 3.0. -?RCS: -?MAKE:d_gethbynm2: Inlibc -?MAKE: -pick add $@ %< -?S:d_gethbynm2 (d_gethbynm2): -?S: This variable conditionally defines the HAS_GETHOSTBYNAME2 symbol, which -?S: indicates to the C program that the gethostbyname2() function is -?S: available to resolve hostnames. -?S:. -?C:HAS_GETHOSTBYNAME2: -?C: This symbol, if defined, indicates that the gethostbyname2() -?C: function is available to resolve hostnames. -?C:. -?H:#$d_gethbynm2 HAS_GETHOSTBYNAME2 /**/ -?H:. -?LINT:set d_gethbynm2 -: see if gethostbyname2 exists -set gethostbyname2 d_gethbynm2 -eval $inlibc - diff --git a/U/d_getnminf.U b/U/d_getnminf.U deleted file mode 100644 index ff671a7..0000000 --- a/U/d_getnminf.U +++ /dev/null @@ -1,49 +0,0 @@ -?RCS: -?RCS: Copyright (c) 2000, Shawn Wagner -?RCS: -?RCS: You may redistribute only under the terms of the Artistic Licence, -?RCS: as specified in the README file that comes with the distribution. -?RCS: You may reuse parts of this distribution only within the terms of -?RCS: that same Artistic Licence; a copy of which may be found at the root -?RCS: of the source tree for dist 3.0. -?RCS: -?MAKE:d_getnminf: cat cc ccflags rm ldflags libs Inlibc -?MAKE: -pick add $@ %< -?S:d_getnminf (d_getnminf): -?S: This variable conditionally defines the HAS_GETNAMEINFO symbol, which -?S: indicates to the C program that the getnameinfo() routine is available -?S: to lookup host names in one data base or another.. -?S:. -?C:HAS_GETNAMEINFO (GETNAMEINFO): -?C: This symbol, if defined, indicates that the getnameinfo() routine is -?C: available to lookup host names in some data base or other. -?C:. -?H:#$d_getnminf HAS_GETNAMEINFO /**/ -?H:. -?LINT:set d_getnminf -: see if getnameinfo exists - along with constants we use -set getnameinfo d_getnminf -eval $inlibc - -if test $d_getnminf = 'define'; then - -echo " " -$cat >test_getnminf.c < -int main(int argc, char **argv) { - int i; - i = NI_MAXHOST + NI_MAXSERV + NI_NOFQDN + NI_NUMERICHOST + NI_NAMEREQD; - i += NI_NUMERICSERV + NI_DGRAM; -} -EOCP - -if $cc $ccflags $ldflags -o test_getnminf test_getnminf.c $libs >/dev/null 2>&1 ; then - d_getnminf='define' - echo "You've got getnameinfo and the netdb constants." >&4 -else - d_getnminf='undef' - echo "You've got getnameinfo but not the NI_* constants! Broken!" >&4 -fi -$rm -f test_getnminf* core - -fi diff --git a/U/d_getpagsz.U b/U/d_getpagsz.U deleted file mode 100644 index af9b702..0000000 --- a/U/d_getpagsz.U +++ /dev/null @@ -1,133 +0,0 @@ -?RCS: $Id: d_getpagsz.U 1.2 Mon, 26 Mar 2001 15:18:14 -0600 dunemush $ -?RCS: -?RCS: Copyright (c) 1991-1993, Raphael Manfredi -?RCS: -?RCS: You may redistribute only under the terms of the Artistic Licence, -?RCS: as specified in the README file that comes with the distribution. -?RCS: You may reuse parts of this distribution only within the terms of -?RCS: that same Artistic Licence; a copy of which may be found at the root -?RCS: of the source tree for dist 3.0. -?RCS: -?RCS: $Log: d_getpagsz.U,v $ -?RCS: Revision 3.0.1.1 1994/10/29 16:13:10 ram -?RCS: patch36: added ?F: line for metalint file checking -?RCS: -?RCS: Revision 3.0 1993/08/18 12:06:14 ram -?RCS: Baseline for dist 3.0 netwide release. -?RCS: -?MAKE:d_getpagsz pagesize: Oldconfig Myread Inlibc cat contains cc ccflags \ - ldflags libs rm Findhdr osname d_sysctlbyname test -?MAKE: -pick add $@ %< -?S:d_getpagsz: -?S: This variable conditionally defines HAS_GETPAGESIZE if getpagesize() -?S: is available to get the system page size. -?S:. -?S:pagesize (pagsize): -?S: This variable holds the size in bytes of a system page. -?S:. -?C:HAS_GETPAGESIZE (GETPAGESIZE): -?C: This symbol, if defined, indicates that the getpagesize system call -?C: is available to get system page size, which is the granularity of -?C: many memory management calls. -?C:. -?X: Don't name it PAGESIZE, this is sometimes used by -?C:PAGESIZE_VALUE (PAGSIZE): -?C: This symbol holds the size in bytes of a system page (obtained via -?C: the getpagesize() system call at configuration time or asked to the -?C: user if the system call is not available). -?C:. -?H:#$d_getpagsz HAS_GETPAGESIZE /**/ -?H:#define PAGESIZE_VALUE $pagesize /* System page size, in bytes */ -?H:. -?F:!page -?T:guess -?LINT:set d_getpagsz -: see if getpagesize exists -set getpagesize d_getpagsz -eval $inlibc - -@if pagesize || PAGESIZE_VALUE -: determine the system page size -echo " " -guess=' (OK to guess)' -case "$pagesize" in -'') - $cat >page.c < -extern int getpagesize(); -int main() -{ - printf("%d\n", getpagesize()); -} -EOP - echo "Computing the granularity of memory management calls..." >&4 - dflt='4096' - case "$d_getpagsz" in - "$define") - if $cc $ccflags $ldflags page.c -o page $libs >/dev/null 2>&1; then - dflt=`./page` - guess='' - else - echo "(I can't seem to compile the test program--guessing)" - fi - ;; - *) - if $cc $ccflags $ldflags page.c -o page $libs -lPW >/dev/null 2>&1; then - dflt=`./page` - guess='' - echo "(For your eyes only: I used the getpagesize() from -lPW.)" - else - if $contains PAGESIZE `./findhdr sys/param.h` >/dev/null 2>&1; then - $cat >page.c < -#include -int main() -{ - printf("%d\n", PAGESIZE); -} -EOP - if $cc $ccflags $ldflags page.c -o page $libs >/dev/null 2>&1; then - dflt=`./page` - guess='' - echo "(Using value of PAGESIZE found in .)" - else - if $test "x$d_sysctlbyname" = "x$define"; then - $cat >page.c < -#include -#include -int main() -{ - int res, pgsize - size_t len; - len = sizeof(pgsize); - res = sysctlbyname("hw.pagesize",&pgsize,&len,NULL,0); - if (res < 0) - res = sysctlbyname("hw_pagesize",&pgsize,&len,NULL,0); - printf("%d\n", res ? -1 : pgsize); -} -EOP - if $cc $ccflags $ldflags page.c -o page $libs >/dev/null 2>&1; then - dflt=`./page` - if $test $dflt -gt 0; then - guess='' - echo "(Using value from sysctlbyname)" - else - dflt='4096' - fi - fi - fi - fi - fi - fi - ;; - esac - ;; -*) dflt="$pagesize"; guess='';; -esac -rp="What is the system page size, in bytes$guess?" -. ./myread -pagesize=$ans -$rm -f page.c page - -@end diff --git a/U/d_gettext.U b/U/d_gettext.U deleted file mode 100644 index c5cd2b3..0000000 --- a/U/d_gettext.U +++ /dev/null @@ -1,41 +0,0 @@ -?RCS: $Id: d_gettext.U 1.2 Wed, 13 Sep 2000 14:49:45 -0500 dunemush $ -?RCS: -?RCS: Copyright (c) 1995, Alan Schwartz -?RCS: -?RCS: You may redistribute only under the terms of the Artistic Licence, -?RCS: as specified in the README file that comes with the distribution. -?RCS: You may reuse parts of this distribution only within the terms of -?RCS: that same Artistic Licence; a copy of which may be found at the root -?RCS: of the source tree for dist 3.0. -?RCS: -?MAKE:d_gettext: Myread cat cc ccflags rm ldflags libs i_libintl -?MAKE: -pick add $@ %< -?S:d_gettext: -?S: Defined if gettext() is available. -?S:. -?C:HAS_GETTEXT: -?C: Defined if gettext is available(). -?C:. -?H:#$d_gettext HAS_GETTEXT /**/ -?H:. -: check for a new-style definitions -echo " " -$cat >test_gettext.c < -#endif -int main(int argc, char **argv) { - return (int) gettext (""); -} -EOCP - -if $cc $ccflags $ldflags -o test_gettext test_gettext.c $libs >/dev/null 2>&1 ; then - d_gettext='define' - echo 'Voila! You seem to have gettext for translations.' >&4 -else - d_gettext='undef' - echo "You don't seem to have gettext. Quel dommage." >&4 -fi -$rm -f test_gettext* core - diff --git a/U/d_gnulibc.U b/U/d_gnulibc.U deleted file mode 100644 index 0e4b38d..0000000 --- a/U/d_gnulibc.U +++ /dev/null @@ -1,70 +0,0 @@ -?RCS: $Id: d_gnulibc.U,v 3.0.1.1 1997/02/28 15:34:33 ram Exp $ -?RCS: -?RCS: Copyright (c) 1996, Andy Dougherty -?RCS: Copyright (c) 1996, Sven Verdoolaege -?RCS: Copyright (c) 1991-1993, Raphael Manfredi -?RCS: -?RCS: You may redistribute only under the terms of the Artistic Licence, -?RCS: as specified in the README file that comes with the distribution. -?RCS: You may reuse parts of this distribution only within the terms of -?RCS: that same Artistic Licence; a copy of which may be found at the root -?RCS: of the source tree for dist 3.0. -?RCS: -?RCS: $Log: d_gnulibc.U,v $ -?RCS: Revision 3.0.1.1 1997/02/28 15:34:33 ram -?RCS: patch61: created -?RCS: -?MAKE:d_gnulibc: Myread Oldconfig Setvar contains rm \ - +cc +ccflags +ldflags +libs -?MAKE: -pick add $@ %< -?S:d_gnulibc: -?S: Defined if we're dealing with the GNU C Library. -?S:. -?C:HAS_GNULIBC: -?C: This symbol, if defined, indicates to the C program that -?C: the GNU C library is being used. -?C:. -?H:#$d_gnulibc HAS_GNULIBC /**/ -?H. -?LINT: set d_gnulibc -?X: gnulibc can be executed by calling this entry point. -?X: Ulrich Drepper doesn't think any other libc does that, -?X: but we check if it says 'GNU C Library' to be sure. -echo " " -echo "Checking for GNU C Library..." >&4 -cat >gnulibc.c </dev/null 2>&1 && \ - ./gnulibc | $contains '^GNU C Library' >/dev/null 2>&1; then - val="$define" - echo "You are using the GNU C Library" >&4 -else -cat >gnulibc.c < -int main() -{ -#ifdef __GLIBC__ - return 0; -#else - return 1; -#endif -} -EOM -if $cc $ccflags $ldflags -o gnulibc gnulibc.c $libs >/dev/null 2>&1 && \ - ./gnulibc; then - val="$define" - echo "You are using the GNU C Library" >&4 -else - val="$undef" - echo "You are not using the GNU C Library" >&4 -fi -fi -$rm -f gnulibc* -set d_gnulibc -eval $setvar - diff --git a/U/d_huge.U b/U/d_huge.U deleted file mode 100644 index 500138a..0000000 --- a/U/d_huge.U +++ /dev/null @@ -1,225 +0,0 @@ -?RCS: $Id: d_huge.U 1.1 Thu, 20 Jul 2000 17:42:54 -0500 dunemush $ -?RCS: -?RCS: Revision 3.0 1993/08/18 12:05:39 ram -?RCS: Baseline for dist 3.0 netwide release. -?RCS: -?MAKE:d_huge_val d_huge d_maxint d_int_max d_maxdouble: Myread cat cc ccflags rm Setvar libs i_values i_limits ldflags -?MAKE: -pick add $@ %< -?S:d_huge_val: -?S: This variable is set if the system defines the HUGE_VAL constant. -?S:. -?S:d_huge: -?S: This variable is set if the system defines the HUGE constant. -?S:. -?S:d_maxint: -?S: This variable is set if the system defines the MAXINT constant. -?S:. -?S:d_int_max: -?S: This variable is set if the system defines the INT_MAX constant. -?S:. -?S:d_maxdouble: -?S: This variable is set if the system defines the MAXDOUBLE constant. -?S:. -?C:HAS_HUGE_VAL: -?C: If defined, this system has the HUGE_VAL constant. We like this, -?C: and don't bother defining the other floats below if we find it. -?C:. -?C:HAS_HUGE: -?C: If defined, this system has the HUGE constant. We like this, and -?C: don't bother defining the other floats below if we find it. -?C:. -?C:HAS_INT_MAX: -?C: If defined, this system has the INT_MAX constant. -?C:. -?C:HAS_MAXINT: -?C: If defined, this system has the MAXINT constant. -?C:. -?C:HAS_MAXDOUBLE: -?C: If defined, this system has the MAXDOUBLE constant. -?C:. -?H:#$d_huge_val HAS_HUGE_VAL /**/ -?H:. -?H:#$d_huge HAS_HUGE /**/ -?H:. -?H:#$d_int_max HAS_INT_MAX /**/ -?H:. -?H:#$d_maxint HAS_MAXINT /**/ -?H:. -?H:#$d_maxdouble HAS_MAXDOUBLE /**/ -?H:. -?M:parse_integer: HAS_HUGE HAS_HUGE_VAL HAS_MAXINT HAS_MAXDOUBLE HAS_INT_MAX -?M:#ifdef HAS_HUGE_VAL -?M:#define HUGE_DOUBLE HUGE_VAL -?M:#else -?M:#ifdef HAS_HUGE -?M:#define HUGE_DOUBLE HUGE -?M:#else -?M:#ifdef HAS_MAXDOUBLE -?M:#define HUGE_DOUBLE MAXDOUBLE -?M:#else -?M:#define HUGE_DOUBLE 2000000000 -?M:#endif -?M:#endif -?M:#endif -?M:#ifdef HAS_INT_MAX -?M:#define HUGE_INT INT_MAX -?M:#else -?M:#ifdef HAS_MAXINT -?M:#define HUGE_INT MAXINT -?M:#else -?M:#define HUGE_INT 2000000000 -?M:#endif -?M:#endif -?M:. -?T:val -?LINT:set d_huge d_huge_val d_maxint d_maxdouble -: see if we have HUGE, HUGE_VAL, MAXINT, or MAXDOUBLE -echo " " -echo "Let's try to figure out a really big double." >&4 - $cat >d_huge.c < -#include -#$i_values I_VALUES -#$i_limits I_LIMITS -#ifdef I_LIMITS -#include -#else -#ifdef I_VALUES -#include -#endif -#endif - -int main() -{ - printf("%f\n",HUGE_VAL); -} -EOCP - if $cc $ccflags $ldflags d_huge.c -o d_huge $libs >/dev/null 2>&1; then - val="$define" - set d_huge_val; eval $setvar - val="$undef" - set d_huge; eval $setvar - set d_maxdouble; eval $setvar - echo "Great. Your system defines HUGE_VAL." >&4 - else - val="$undef" - set d_huge_val; eval $setvar - echo "Your system doesn't have HUGE_VAL. Maybe HUGE?" >&4 - $cat >d_huge.c < -#include -#$i_values I_VALUES -#$i_limits I_LIMITS -#ifdef I_LIMITS -#include -#else -#ifdef I_VALUES -#include -#endif -#endif -int main() -{ - printf("%f\n",HUGE); -} -EOCP - - if $cc $ccflags $ldflags d_huge.c -o d_huge $libs >/dev/null 2>&1; then - val="$define" - set d_huge; eval $setvar - val="$undef" - set d_maxdouble; eval $setvar - echo "Good. Your system defines HUGE." >&4 - else - val="$undef" - set d_huge; eval $setvar - echo "Hmm. Your system doesn't define HUGE. MAX_DOUBLE?" >&4 - $cat >d_huge.c < -#include -#$i_limits I_LIMITS -#ifdef I_LIMITS -#include -#else -#$i_values I_VALUES -#ifdef I_VALUES -#include -#endif -#endif -int main() -{ - printf("%f\n",MAX_DOUBLE); -} -EOCP - - if $cc $ccflags $ldflags d_huge.c -o d_huge $libs >/dev/null 2>&1; then - val="$define" - echo "Ok, you've got MAXDOUBLE." >&4 - else - val="$undef" - echo "Nope, no MAXDOUBLE either. We'll guess one." >&4 - fi - set d_maxdouble; eval $setvar - fi -fi - - -echo " " -echo "Let's try to figure out a really big int, too." >&4 - $cat >d_huge.c < -#include -#$i_limits I_LIMITS -#ifdef I_LIMITS -#include -#else -#$i_values I_VALUES -#ifdef I_VALUES -#include -#endif -#endif -int main() -{ - printf("%d\n",INT_MAX); -} -EOCP - -if $cc $ccflags $ldflags d_huge.c -o d_huge $libs >/dev/null 2>&1; then - val="$define" - set d_int_max; eval $setvar - val="$undef" - set d_maxint; eval $setvar - echo "Ok, you've got INT_MAX." >&4 -else - val="$undef" - echo "No INT_MAX. Maybe MAXINT?" >&4 - set d_int_max; eval $setvar - $cat >d_huge.c < -#include -#$i_limits I_LIMITS -#ifdef I_LIMITS -#include -#else -#$i_values I_VALUES -#ifdef I_VALUES -#include -#endif -#endif -int main() -{ - printf("%d\n",MAXINT); -} -EOCP - if $cc $ccflags $ldflags d_huge.c -o d_huge $libs >/dev/null 2>&1; then - val="$define" - echo "Ok, you've got MAXINT." >&4 - set d_maxint; eval $setvar - else - val="$undef" - echo "No MAXINT. I give up. I'll take a guess." >&4 - set d_maxint; eval $setvar - fi -fi - -$rm -f d_huge* - diff --git a/U/d_ieee.U b/U/d_ieee.U deleted file mode 100644 index 9124fc3..0000000 --- a/U/d_ieee.U +++ /dev/null @@ -1,55 +0,0 @@ -?RCS: $Id: d_ieee.U 1.1 Thu, 20 Jul 2000 17:42:54 -0500 dunemush $ -?RCS: -?RCS: Copyright (c) 1995, Alan Schwartz -?RCS: -?RCS: You may redistribute only under the terms of the Artistic Licence, -?RCS: as specified in the README file that comes with the distribution. -?RCS: You may reuse parts of this distribution only within the terms of -?RCS: that same Artistic Licence; a copy of which may be found at the root -?RCS: of the source tree for dist 3.0. -?RCS: -?MAKE:d_ieee: Myread cat cc ccflags rm ldflags -?MAKE: -pick add $@ %< -?S:d_ieee: -?S: Defined if the machine supports IEEE math - that is, can safely -?S: return NaN or Inf rather than crash on bad math. -?S:. -?C:HAS_IEEE_MATH: -?C: Defined if the machine supports IEEE math - that is, can safely -?C: return NaN or Inf rather than crash on bad math. -?C:. -?H:#$d_ieee HAS_IEEE_MATH /**/ -?H:. -: check for a safe ieee -echo " " -echo "Let's see if your math functions handle errors nicely..." >&4 -$cat >test_ieee.c <<'EOCP' -#include -#include - -int main() { - double x; - x = pow(-1,.5); - x = pow(10000,10000); - printf("define\n"); - exit(0); -} -EOCP - -if $cc $ccflags $ldflags -o test_ieee test_ieee.c -lm >/dev/null 2>&1 ; then - d_ieee=`./test_ieee` - if test $d_ieee = define ; then - echo "Great! They can." >&4 - else - echo "Nope, they crash and burn." >&4 - d_ieee='undef' - fi -else - $cat <d_ipv6.c < -#endif -#ifdef I_SYS_SOCK -#include -#endif -#ifdef I_NETINET_IN -#include -#else -#ifdef I_SYS_IN -#include -#endif -#endif -#include -main() -{ - struct sockaddr_in6 test; - int foo = AF_INET6; - printf("%d\n", foo); -} -EOCP -if $cc $ccflags $ldflags d_ipv6.c -o d_ipv6 $libs >/dev/null 2>&1; then - val="$define" - set d_ipv6; eval $setvar - echo "IPv6 structures found." >&4 -else - val="$undef" - set d_ipv6; eval $setvar - echo "No IPv6 structures found. No problem." >&4 -fi diff --git a/U/d_keepsig.U b/U/d_keepsig.U deleted file mode 100644 index 9d46f6a..0000000 --- a/U/d_keepsig.U +++ /dev/null @@ -1,78 +0,0 @@ -?RCS: $Id: d_keepsig.U 1.1 Thu, 20 Jul 2000 17:42:54 -0500 dunemush $ -?RCS: -?RCS: Copyright (c) 1991-1993, Raphael Manfredi -?RCS: -?RCS: You may redistribute only under the terms of the Artistic Licence, -?RCS: as specified in the README file that comes with the distribution. -?RCS: You may reuse parts of this distribution only within the terms of -?RCS: that same Artistic Licence; a copy of which may be found at the root -?RCS: of the source tree for dist 3.0. -?RCS: -?RCS: $Log: d_keepsig.U,v $ -?RCS: Revision 3.0.1.3 1995/01/11 15:26:25 ram -?RCS: patch45: protected "sh -c" within backquotes for Linux and SGI -?RCS: -?RCS: Revision 3.0.1.2 1994/10/29 16:13:59 ram -?RCS: patch36: call ./bsd explicitely instead of relying on PATH -?RCS: -?RCS: Revision 3.0.1.1 1993/10/16 13:48:47 ram -?RCS: patch12: comment for SIGNALS_KEPT was the other way round -?RCS: -?RCS: Revision 3.0 1993/08/18 12:06:26 ram -?RCS: Baseline for dist 3.0 netwide release. -?RCS: -?MAKE:d_keepsig: cat cc ccflags rm Guess contains echo n c Setvar d_sigaction ldflags -?MAKE: -pick add $@ %< -?S:d_keepsig: -?S: This variable contains the eventual value of the SIGNALS_KEPT symbol, -?S: which indicates to the C program if signal handlers need not reinstated -?S: after receipt of a signal. -?S:. -?C:SIGNALS_KEPT (PERSISTENT_SIGNAL): -?C: This symbol is defined if signal handlers needn't be reinstated after -?C: receipt of a signal. -?C:. -?H:#$d_keepsig SIGNALS_KEPT /**/ -?H:. -?LINT:set d_keepsig -: see if signals are kept -val="$undef" -echo " " -echo "Checking to see if signal handlers stick around..." >&4 -if test ${d_sigaction} = "$define"; then - echo "You've got sigaction, so we can force 'em to." >&4 - val="$define" -else - $cat >try.c <<'EOCP' -foo() {} - -int main() -{ - signal(2, foo); - kill(getpid(), 2); - kill(getpid(), 2); - printf("abc\n"); -} -EOCP - if $cc -o try $ccflags $ldflags try.c >/dev/null 2>&1; then - sh -c ./try >try.out 2>/dev/null - if $contains abc try.out >/dev/null 2>&1; then - echo "Yes, they do." - val="$define"; - else - echo "No, they don't." - fi - else - $echo $n "(I can't seem to compile the test program. Assuming $c" - if ./bsd; then - echo "they do.)" - val="$define" - else - echo "they don't.)" - fi - fi -fi -set d_keepsig -eval $setvar -$rm -f try* - diff --git a/U/d_lua.U b/U/d_lua.U deleted file mode 100644 index 1885224..0000000 --- a/U/d_lua.U +++ /dev/null @@ -1,113 +0,0 @@ -?MAKE: d_lua: Loc test xlibpth libpth Csym Setvar Inhdr libs -?MAKE: -pick add $@ %< -# Function to check for loca LUA installation -# -checkLocalLua() { - myincs="lua5.1 lua-5.1.4" - otherincs="" - thisincl="" - for thisincl in $myincs; do - if $test -r "$toplev/$thisincl/src/lua.h" ; then - lua_h_path="$toplev/$thisincl/src" - elif $test -r "$toplev/$thisincl/lua.h" ; then - lua_h_path="$toplev/$thisincl" - else - otherincs="$otherincs $toplev/$thisincl $toplev/$thisincl/src" - fi - done - if $test "$lua_h_path" ; then - echo "Found -llua" >&4 -?X: try to link in local lua library into ldflags= -?X: Normally when you install the src in our directory it will be in the lua/src directory.. - if $test -f "$lua_h_path/liblua.a"; then - ldflags="$ldflags -L$lua_h_path" - libs="$libs -llua" - else - echo "Could not locate local LUA library." - echo "Either install LUA development global libraries or compile your local LUA installation"; - exit 1; - fi - fi - -} - -?X: see if lua exists, otherwise end configure script -echo " " - -echo "Let's search for LUA header files." >&4 - -myincs="/usr/include $locincpth" -otherincs="" -for thisincl in $myincs; do - otherincs="$otherincs $thisincl/lua5.1" -done - -lua_h_path="" -for thisincl in $myincs $otherincs; do - if $test -r "$thisincl/lua.h"; then - lua_h_path="$thisincl" - fi -done - -if $test -z "$lua_h_path" ; then - echo "Unable to find global lua.h header. Checking local directories." >&4 - checkLocalLua -else - echo "Found LUA Header path at $lua_h_path">&4 - echo "Searching for LUA Library" -?X: Could probably make this a function in libs.U and cut down on this kludge - thislib="lua5.1" - if xxx=`./loc lib$thislib.$so.[0-9]'*' X $libpth`; $test -f "$xxx"; then - echo "Found -l$thislib (shared)." - case " $libs " in - *"-l$thislib "*);; - *) libs="$libs -l$thislib";; - esac - elif xxx=`./loc lib$thislib.$so X $libpth` ; $test -f "$xxx"; then - echo "Found -l$thislib (shared)." - case " $libs " in - *"-l$thislib "*);; - *) libs="$libs -l$thislib";; - esac - elif xxx=`./loc lib$thislib$_a X $libpth`; $test -f "$xxx"; then - echo "Found -l$thislib." - case " $libs " in - *"-l$thislib "*);; - *) libs="$libs -l$thislib";; - esac -?X: Don't forget about OS/2 where -lmalloc is spelled out malloc.a - elif xxx=`./loc $thislib$_a X $libpth`; $test -f "$xxx"; then - echo "Found -l$thislib." - case " $libs " in - *"-l$thislib "*);; - *) libs="$libs -l$thislib";; - esac - elif xxx=`./loc lib${thislib}_s$_a X $libpth`; $test -f "$xxx"; then - echo "Found -l${thislib}_s." - case " $dflt " in - *"-l$thislib "*);; - *) libs="$libs -l${thislib}_s";; - esac - elif xxx=`./loc Slib$thislib$_a X $xlibpth`; $test -f "$xxx"; then - echo "Found -l$thislib." - case " $libs " in - *"-l$thislib "*);; - *) libs="$libs -l$thislib";; - esac - else - echo "Can't find global LUA Library. Checking Local." - checkLocalLua - fi - - -fi - -if test -z "$lua_h_path"; then - echo "I Give up..">&4 - echo "Looked in $otherincs for it" >&4 - exit 1; -fi - -ccflags="$ccflags -I$lua_h_path" - - diff --git a/U/d_memcpy.U b/U/d_memcpy.U deleted file mode 100644 index c7bee0b..0000000 --- a/U/d_memcpy.U +++ /dev/null @@ -1,63 +0,0 @@ -?RCS: $Id: d_memcpy.U 1.1 Thu, 20 Jul 2000 17:42:54 -0500 dunemush $ -?RCS: -?RCS: Copyright (c) 1991-1993, Raphael Manfredi -?RCS: -?RCS: You may redistribute only under the terms of the Artistic Licence, -?RCS: as specified in the README file that comes with the distribution. -?RCS: You may reuse parts of this distribution only within the terms of -?RCS: that same Artistic Licence; a copy of which may be found at the root -?RCS: of the source tree for dist 3.0. -?RCS: -?RCS: $Log: d_memcpy.U,v $ -?RCS: Revision 3.0.1.1 1993/09/13 16:02:58 ram -?RCS: patch10: removed text recommending bcopy over memcpy (WAD) -?RCS: -?RCS: Revision 3.0 1993/08/18 12:06:34 ram -?RCS: Baseline for dist 3.0 netwide release. -?RCS: -?MAKE:d_memcpy d_memmove: Inlibc -?MAKE: -pick add $@ %< -?S:d_memcpy: -?S: This variable conditionally defines the HAS_MEMCPY symbol, which -?S: indicates to the C program that the memcpy() routine is available -?S: to copy blocks of memory. -?S:. -?S:d_memmove: -?S: This variable conditionally defines the HAS_MEMMOVE symbol, which -?S: indicates to the C program that the memmove() routine is available -?S: to copy overlapping blocks of memory. -?S:. -?C:HAS_MEMCPY (MEMCPY): -?C: This symbol, if defined, indicates that the memcpy routine is available -?C: to copy blocks of memory. If not, it will be mapped to bcopy -?C: in confmagic.h -?C:. -?C:HAS_MEMMOVE (MEMMOVE): -?C: This symbol, if defined, indicates that the memmove routine is available -?C: to copy blocks of memory. If not, it will be mapped to bcopy -?C:. -?H:#$d_memcpy HAS_MEMCPY /**/ -?H:. -?H:#$d_memmove HAS_MEMMOVE /**/ -?H:. -?M:memcpy:HAS_MEMCPY -?M:#ifndef HAS_MEMCPY -?M:#ifndef memcpy -?M:#define memcpy(d,s,l) bcopy((s),(d),(l)) -?M:#endif -?M:#endif -?M:. -?M:memmove:HAS_MEMMOVE -?M:#ifndef HAS_MEMMOVE -?M:#ifndef memmove -?M:#define memmove(d,s,l) bcopy((s),(d),(l)) -?M:#endif -?M:#endif -?M:. -?LINT:set d_memcpy d_memmove -: see if memcpy exists -set memcpy d_memcpy -eval $inlibc -set memmove d_memmove -eval $inlibc - diff --git a/U/d_memmove.U b/U/d_memmove.U deleted file mode 100644 index e69de29..0000000 diff --git a/U/d_newstyle.U b/U/d_newstyle.U deleted file mode 100644 index 0273797..0000000 --- a/U/d_newstyle.U +++ /dev/null @@ -1,41 +0,0 @@ -?RCS: $Id: d_newstyle.U 1.2 Sat, 30 Jun 2001 08:59:12 -0500 dunemush $ -?RCS: -?RCS: Copyright (c) 1995, Alan Schwartz -?RCS: -?RCS: You may redistribute only under the terms of the Artistic Licence, -?RCS: as specified in the README file that comes with the distribution. -?RCS: You may reuse parts of this distribution only within the terms of -?RCS: that same Artistic Licence; a copy of which may be found at the root -?RCS: of the source tree for dist 3.0. -?RCS: -?MAKE:d_newstyle: Myread cat cc ccflags rm ldflags -?MAKE: -pick add $@ %< -?S:d_newstyle: -?S: Defined if new-style function definitions are allowable. -?S:. -?C:CAN_NEWSTYLE: -?C: Defined if new-style function definitions are allowable. -?C: If they are, we can avoid some warnings that you get if -?C: you declare char arguments in a prototype and use old-style -?C: function definitions, which implicitly promote them to ints. -?C:. -?H:#$d_newstyle CAN_NEWSTYLE /**/ -?H:. -: check for a new-style definitions -echo " " -$cat >test_newstyle.c <<'EOCP' -#include -int main(int argc, char **argv) { - exit(0); -} -EOCP - -if $cc $ccflags $ldflags -o test_newstyle test_newstyle.c >/dev/null 2>&1 ; then - d_newstyle='define' - echo 'Your compiler accepts new-style function definitions.' >&4 -else - d_newstyle='undef' - echo "Your compiler DOESN'T accept new-style function definitions." >&4 -fi -$rm -f test_newstyle* core - diff --git a/U/d_open3.U b/U/d_open3.U deleted file mode 100644 index 1e8521f..0000000 --- a/U/d_open3.U +++ /dev/null @@ -1,90 +0,0 @@ -?RCS: $Id: d_open3.U 1.1 Thu, 20 Jul 2000 17:42:54 -0500 dunemush $ -?RCS: -?RCS: Copyright (c) 1991-1993, Raphael Manfredi -?RCS: -?RCS: You may redistribute only under the terms of the Artistic Licence, -?RCS: as specified in the README file that comes with the distribution. -?RCS: You may reuse parts of this distribution only within the terms of -?RCS: that same Artistic Licence; a copy of which may be found at the root -?RCS: of the source tree for dist 3.0. -?RCS: -?RCS: $Log: d_open3.U,v $ -?RCS: Revision 3.0.1.2 1997/02/28 15:37:12 ram -?RCS: patch61: added ?F: metalint hint -?RCS: -?RCS: Revision 3.0.1.1 1995/07/25 13:58:26 ram -?RCS: patch56: added knowledge of the O_NONBLOCK symbol -?RCS: -?RCS: Revision 3.0 1993/08/18 12:06:44 ram -?RCS: Baseline for dist 3.0 netwide release. -?RCS: -?MAKE:d_open3: test cc cat ccflags ldflags libs h_fcntl h_sysfile rm Setvar Findhdr -?MAKE: -pick add $@ %< -?X: It would be easy to separate the h_O_stuff from this. -?X: Is there a reason to do so? -- HMS -?S:d_open3: -?S: This variable conditionally defines the HAS_OPEN3 manifest constant, -?S: which indicates to the C program that the 3 argument version of -?S: the open(2) function is available. -?S:. -?C:HAS_OPEN3 (OPEN3): -?C: This manifest constant lets the C program know that the three -?C: argument form of open(2) is available. -?C:. -?H:#$d_open3 HAS_OPEN3 /**/ -?H:. -?W:%<:O_RDONLY O_WRONLY O_RDWR O_NDELAY O_APPEND O_SYNC O_CREAT O_TRUNC -?W:%<:O_EXCL O_NONBLOCK -?F:!open3 -?LINT:set d_open3 -?LINT:change h_fcntl h_sysfile -: Locate the flags for 'open()' -echo " " -$cat >open3.c <<'EOCP' -#include -#ifdef I_FCNTL -#include -#endif -#ifdef I_SYS_FILE -#include -#endif -int main() { - if(O_RDONLY); -#ifdef O_TRUNC - exit(0); -#else - exit(1); -#endif -} -EOCP -: check sys/file.h first to get FREAD on Sun -if $test "`./findhdr sys/file.h`" && \ - $cc $ccflags $ldflags "-DI_SYS_FILE" open3.c -o open3 $libs >/dev/null 2>&1 ; then - h_sysfile=true; - echo " defines the O_* constants..." >&4 - if ./open3; then - echo "and you have the 3 argument form of open()." >&4 - val="$define" - else - echo "but not the 3 argument form of open(). Oh, well." >&4 - val="$undef" - fi -elif $test "`./findhdr fcntl.h`" && \ - $cc $ccflags $ldflags "-DI_FCNTL" open3.c -o open3 $libs >/dev/null 2>&1 ; then - h_fcntl=true; - echo " defines the O_* constants..." >&4 - if ./open3; then - echo "and you have the 3 argument form of open()." >&4 - val="$define" - else - echo "but not the 3 argument form of open(). Oh, well." >&4 - val="$undef" - fi -else - val="$undef" - echo "I can't find the O_* constant definitions! You got problems." >&4 -fi -set d_open3 -eval $setvar -$rm -f open3* - diff --git a/U/d_random.U b/U/d_random.U deleted file mode 100644 index 801ab70..0000000 --- a/U/d_random.U +++ /dev/null @@ -1,53 +0,0 @@ -?RCS: $Id: d_random.U 1.4 Fri, 15 Feb 2002 16:56:28 -0600 dunemush $ -?RCS: -?RCS: Copyright (c) 1995, Alan Schwartz -?RCS: Based on d_strchr.U -?RCS: -?MAKE:d_random d_lrand48 d_rand: Inlibc -?MAKE: -pick add $@ %< -?S:d_random: -?S: This variable conditionally defines HAS_RANDOM if random() is there -?S:. -?S:d_lrand48: -?S: This conditionally defines HAS_LRAND48 if lrand45() is there -?S:. -?S:d_rand: -?S: This conditionally defines HAS_RAND if rand() is there -?S:. -?C:HAS_RANDOM: -?C: Have we got random(), our first choice for number generation? -?C:. -?C:HAS_LRAND48: -?C: Have we got lrand48(), our second choice? -?C:. -?C:HAS_RAND: -?C: Have we got rand(), our last choice? -?C:. -?H:#$d_random HAS_RANDOM /**/ -?H:#$d_lrand48 HAS_LRAND48 /**/ -?H:#$d_rand HAS_RAND /**/ -?H:. -?M:random: HAS_RANDOM HAS_LRAND48 HAS_RAND -?M:#ifndef HAS_RANDOM -?M:#ifndef random -?M:#ifdef HAS_LRAND48 -?M:#define random lrand48 -?M:#define srandom srand48 -?M:#else -?M:#ifdef HAS_RAND -?M:#define random rand -?M:#define srandom srand -?M:#endif -?M:#endif -?M:#endif -?M:#endif -?M:. -?LINT:set d_lrand48 d_rand d_random -: random, lrand48, or rand -set random d_random -eval $inlibc -set lrand48 d_lrand48 -eval $inlibc -set rand d_rand -eval $inlibc - diff --git a/U/d_rlimit.U b/U/d_rlimit.U deleted file mode 100644 index f63f507..0000000 --- a/U/d_rlimit.U +++ /dev/null @@ -1,27 +0,0 @@ -?RCS: $Id: d_rlimit.U 1.1 Thu, 20 Jul 2000 17:42:54 -0500 dunemush $ -?RCS: -?RCS: Copyright (c) 1995, Alan Schwartz -?RCS: -?RCS: -?X: We may need to include and FIXME -?X:INC: i_sysresrc i_systime -?MAKE:d_rlimit: Inlibc -?MAKE: -pick add $@ %< -?S:d_rlimit: -?S: This variable conditionally defines the HAS_GETRLIMIT symbol, which -?S: indicates that the getrlimit() routine exists. The getrlimit() routine -?S: supports getting resource limits, and there should be a setrlimit() too -?S: We probably need to include and . -?S:. -?C:HAS_GETRLIMIT (RLIMIT GETRLIMIT): -?C: This symbol, if defined, indicates that the getrlimit() routine is -?C: available to get resource limits. Probably means setrlimit too. -?C: Inclusion of and may be necessary. -?C:. -?H:#$d_rlimit HAS_GETRLIMIT /**/ -?H:. -?LINT:set d_rlimit -: see if getrlimit exists -set getrlimit d_rlimit -eval $inlibc - diff --git a/U/d_round.U b/U/d_round.U deleted file mode 100644 index 6eaaaca..0000000 --- a/U/d_round.U +++ /dev/null @@ -1,20 +0,0 @@ -?RCS: -?RCS: -?RCS: -?MAKE:d_round: Inlibc -?MAKE: -pick add $@ %< -?S:d_round: -?S: This variable conditionally defines the HAS_ROUND symbol, which -?S: indicates that the round() routine exists. -?S:. -?C:HAS_ROUND: -?C: This symbol, if defined, indicates that the round() routine is -?C: available to get some system parameters. -?C:. -?H:#$d_round HAS_ROUND /**/ -?H:. -?LINT:set d_round d_roundbyname -: see if round exists -set round d_round -eval $inlibc - diff --git a/U/d_sendmail.U b/U/d_sendmail.U deleted file mode 100644 index 2656216..0000000 --- a/U/d_sendmail.U +++ /dev/null @@ -1,32 +0,0 @@ -?RCS: $Id: d_sendmail.U 1.2 Tue, 30 Sep 2003 18:01:23 -0500 dunemush $ -?RCS: -?RCS: -?MAKE:d_sendmail : sendmail Setvar Oldconfig Csym Loc test -?MAKE: -pick add $@ %< -?S:d_sendmail: -?S: This variable is defined if sendmail is available. -?S:. -?C:SENDMAIL: -?C: This symbol contains the full pathname to sendmail. -?C:. -?C:HAS_SENDMAIL: -?C: If defined, we have sendmail. -?C:. -?H:#$d_sendmail HAS_SENDMAIL /**/ -?H:#define SENDMAIL "$sendmail" -?H:. -?W:%<:SENDMAIL HAS_SENDMAIL -?LINT:set d_sendmail -: have we got sendmail? -echo " " -echo "Checking to see if we can use sendmail..." -if $test -f $sendmail; then - echo "Looks like sendmail is in $sendmail" - val="$define" -else - echo "Nope, out of luck." - val="$undef" -fi -set d_sendmail -eval $setvar - diff --git a/U/d_sigchld.U b/U/d_sigchld.U deleted file mode 100644 index 0c712a2..0000000 --- a/U/d_sigchld.U +++ /dev/null @@ -1,74 +0,0 @@ -?RCS: $Id: d_sigchld.U 1.1 Thu, 20 Jul 2000 17:42:54 -0500 dunemush $ -?RCS: -?RCS: Revision 3.0 1993/08/18 12:05:39 ram -?RCS: Baseline for dist 3.0 netwide release. -?RCS: -?MAKE:d_sigchld d_sigcld: Myread cat cc ccflags rm Setvar libs ldflags d_lua -?MAKE: -pick add $@ %< -?S:d_sigchld: -?S: This variable is set if the system defines SIGCHLD -?S:. -?S:d_sigcld: -?S: This variable is set if the system defines SIGCLD (the SysV -?S: version of SIGCHLD) -?S:. -?C:HAS_SIGCHLD: -?C: If defined, this system has the SIGCHLD constant. -?C:. -?C:HAS_SIGCLD: -?C: If defined, this system has the SIGCLD constant (SysVish SIGCHLD). -?C:. -?H:#$d_sigchld HAS_SIGCHLD /**/ -?H:. -?H:#$d_sigcld HAS_SIGCLD /**/ -?H:. -?M:SIGCHLD: HAS_SIGCHLD -?M:#ifndef HAS_SIGCHLD -?M:#define SIGCHLD SIGCLD -?M:#endif -?M:. -?M:SIGCLD: HAS_SIGCLD -?M:#ifndef HAS_SIGCLD -?M:#define SIGCLD SIGCHLD -?M:#endif -?M:. -?T:val -?LINT:set d_sigchld d_sigcld d_lua -: see if we have SIGCHLD, SIGCLD, or both -echo " " -echo "How should a child signal a parent?" >&4 -$cat >d_sigchld.c < -#include -int main() -{ - printf("%d\n",SIGCHLD); -} -EOCP -if $cc $ccflags $ldflags d_sigchld.c -o d_sigchld $libs >/dev/null 2>&1; then - val="$define" - set d_sigchld; eval $setvar - echo "SIGCHLD works." -else - val="$undef" - set d_sigchld; eval $setvar - echo "SIGCHLD doesn't work." -fi - -$cat >d_sigchld.c < -#include -int main() -{ - printf("%d\n",SIGCLD); -} -EOCP -if $cc $ccflags $ldflags d_sigchld.c -o d_sigchld $libs >/dev/null 2>&1; then - val="$define" - set d_sigcld; eval $setvar - echo "SIGCLD works." -else - val="$undef" - set d_sigcld; eval $setvar - echo "SIGCLD doesn't work." -fi diff --git a/U/d_signalproto.U b/U/d_signalproto.U deleted file mode 100644 index c1ad548..0000000 --- a/U/d_signalproto.U +++ /dev/null @@ -1,78 +0,0 @@ -?RCS: $Id: d_signalproto.U 1.1 Thu, 20 Jul 2000 17:42:54 -0500 dunemush $ -?RCS: -?RCS: Copyright (c) 1991-1993, Raphael Manfredi -?RCS: -?RCS: You may redistribute only under the terms of the Artistic Licence, -?RCS: as specified in the README file that comes with the distribution. -?RCS: You may reuse parts of this distribution only within the terms of -?RCS: that same Artistic Licence; a copy of which may be found at the root -?RCS: of the source tree for dist 3.0. -?RCS: -?RCS: $Log: d_keepsig.U,v $ -?RCS: Revision 3.0.1.3 1995/01/11 15:26:25 ram -?RCS: patch45: protected "sh -c" within backquotes for Linux and SGI -?RCS: -?RCS: Revision 3.0.1.2 1994/10/29 16:13:59 ram -?RCS: patch36: call ./bsd explicitely instead of relying on PATH -?RCS: -?RCS: Revision 3.0.1.1 1993/10/16 13:48:47 ram -?RCS: patch12: comment for SIGNALS_KEPT was the other way round -?RCS: -?RCS: Revision 3.0 1993/08/18 12:06:26 ram -?RCS: Baseline for dist 3.0 netwide release. -?RCS: -?MAKE:d_signalproto: cat cc ccflags rm Guess echo Setvar prototype signal_t ldflags -?MAKE: -pick add $@ %< -?S:d_signalproto: -?S: This variable tells us if we can safely prototype signal() as follows: -?S: Signal_t(*Sigfunc) _((int)); -?S: extern Sigfunc signal _((int signo, Sigfunc func)); -?S:. -?C:CAN_PROTOTYPE_SIGNAL: -?C: This symbol is defined if we can safely prototype our rewritten -?C: signal() function as: -?C: Signal_t(*Sigfunc) _((int)); -?C: extern Sigfunc signal _((int signo, Sigfunc func)); -?C:. -?H:#$d_signalproto CAN_PROTOTYPE_SIGNAL /**/ -?H:. -?LINT:set d_signalproto -: can we prototype signal ourselves -val="$undef" -echo " " -echo "Checking to see if we can declare or prototype signal()..." >&4 -if test ${prototype} = "$define"; then - $cat >try.c < -#include -#ifdef signal -#undef signal -#endif -typedef ${signal_t} (*Sigfunc) (int); -extern Sigfunc signal (int signo, Sigfunc func); -int main() -{ printf("no op\n"); } -EOCP -else - $cat >try.c < -#include -#ifdef signal -#undef signal -#endif -typedef ${signal_t} (*Sigfunc) (); -extern Sigfunc signal (); -int main() -{ printf("no op\n"); } -EOCP -fi -if $cc -o try $ccflags $ldflags try.c >/dev/null 2>&1; then - $echo "Looks like we can." - val="$define"; -else - $echo "Looks like we can't." -fi -set d_signalproto -eval $setvar -$rm -f try* - diff --git a/U/d_signed_stdio.U b/U/d_signed_stdio.U deleted file mode 100644 index 68f9f98..0000000 --- a/U/d_signed_stdio.U +++ /dev/null @@ -1,56 +0,0 @@ -?RCS: $Id: d_signed_stdio.U 1.1 Thu, 20 Jul 2000 17:42:54 -0500 dunemush $ -?RCS: -?RCS: Copyright (c) 1995, Alan Schwartz -?RCS: -?RCS: You may redistribute only under the terms of the Artistic Licence, -?RCS: as specified in the README file that comes with the distribution. -?RCS: You may reuse parts of this distribution only within the terms of -?RCS: that same Artistic Licence; a copy of which may be found at the root -?RCS: of the source tree for dist 3.0. -?RCS: -?MAKE:d_signed_stdio: Myread cat cc ccflags rm ldflags -?MAKE: -pick add $@ %< -?S:d_signed_stdio: -?S: Defined if file desriptors in the stdio library are signed chars, -?S: rather than unsigned chars, for example, in SunOS 4.1.x. -?S: This is bad, because descriptors > 127 break. -?S:. -?C:HAS_SIGNED_STDIO: -?C: Defined if file desriptors in the stdio library are signed chars, -?C: rather than unsigned chars, for example, in SunOS 4.1.x. -?C: This is bad, because descriptors > 127 break. -?C:. -?H:#$d_signed_stdio HAS_SIGNED_STDIO /**/ -?H:. -: check for broken brain-damaged signed char stdio calls. -echo " " -echo "Let's see if your stdio uses signed chars instead of unsigned for fd's..." >&4 - -$cat >test_signed_stdio.c <<'EOCP' -#include -int main() { - FILE foo; - foo._file = 128; - if (foo._file == 128) - printf("undef\n"); /* good stdio */ - else - printf("define\n"); /* bad stdio */ -} -EOCP - -if $cc $ccflags $ldflags -o test_signed_stdio test_signed_stdio.c >/dev/null 2>&1 ; then - d_signed_stdio=`./test_signed_stdio` - if test $d_signed_stdio = define ; then - echo "Alas, you've got signed char stdio. Have to work around that." >&4 - else - echo "Cool. Your stdio uses unsigned chars like it should." >&4 - fi -else - $cat <&4 - val="$define" -else - echo 'sigprocmask NOT found.' >&4 - val="$undef" -fi -?X: -?X: Solaris 2.5_x86 with SunWorks Pro C 3.0.1 doesn't have a complete -?X: sigaction structure if compiled with cc -Xc. This compile test -?X: will fail then. -?X: -$cat > set.c <<'EOP' -#include -#include -#include -main() -{ - sigset_t mask, oldmask; - sigprocmask(SIG_SETMASK, &mask, &oldmask); -} -EOP -if $cc $ccflags $ldflags -o set set.c $libs >/dev/null 2>&1; then - : -else - echo "But you don't seem to have a working sigprocmask." >&4 - val="$undef" -fi -set d_sigprocmask; eval $setvar -$rm -f set set$_o set.c - diff --git a/U/d_snprintf.U b/U/d_snprintf.U deleted file mode 100644 index 0dfb6e5..0000000 --- a/U/d_snprintf.U +++ /dev/null @@ -1,39 +0,0 @@ -?RCS: $Id: d_snprintf.U 1.1 Thu, 01 Feb 2001 14:47:02 -0600 dunemush $ -?RCS: -?RCS: Copyright (c) 1991-1993, Raphael Manfredi -?RCS: -?RCS: You may redistribute only under the terms of the Artistic Licence, -?RCS: as specified in the README file that comes with the distribution. -?RCS: You may reuse parts of this distribution only within the terms of -?RCS: that same Artistic Licence; a copy of which may be found at the root -?RCS: of the source tree for dist 3.0. -?RCS: -?RCS: $Log: d_snprintf.U,v $ -?RCS: Revision 3.0 1993/08/18 12:07:59 ram -?RCS: Baseline for dist 3.0 netwide release. -?RCS: -?MAKE:d_snprintf: Guess cat +cc +ccflags Csym Setvar -?MAKE: -pick add $@ %< -?S:d_snprintf: -?S: This variable conditionally defines the HAS_SNPRINTF symbol, which -?S: indicates to the C program that the snprintf() routine is available. -?S:. -?C:HAS_SNPRINTF: -?C: This symbol, if defined, indicates that the snprintf routine is -?C: available. If not, we use sprintf, which is less safe. -?C:. -?H:#$d_snprintf HAS_SNPRINTF /**/ -?H:. -?LINT:set d_snprintf -: see if snprintf exists -echo " " -if set snprintf val -f d_snprintf; eval $csym; $val; then - echo 'snprintf() found.' >&4 - val="$define" -else - echo 'snprintf() NOT found.' >&4 - val="$undef" -fi -set d_snprintf -eval $setvar - diff --git a/U/d_socklen.U b/U/d_socklen.U deleted file mode 100644 index 320e6b4..0000000 --- a/U/d_socklen.U +++ /dev/null @@ -1,38 +0,0 @@ -?MAKE: d_socklen: libs sockethdr i_systypes i_syssock cc ccflags ldflags Setvar -?MAKE: -pick add $@ %< -?S:d_socklen: -?S: This variable is set if the system defines the socklen_t type. -?S:. -?C:HAS_SOCKLEN_T: -?C: If defined, this system has the socklen_t type. -?C:. -?H:#$d_socklen HAS_SOCKLEN_T /**/ -?H:. -?LINT:set d_socklen -: see if we have socklen_t. -echo " " -$cat >d_socklen.c < -#endif -#ifdef I_SYS_SOCKET -#include -#endif -#include -main() -{ - socklen_t test = 1; - printf("%d\n",test); -} -EOCP -if $cc $ccflags $ldflags d_socklen.c -o d_socklen $libs >/dev/null 2>&1; then - val="$define" - set d_socklen; eval $setvar - echo "socklen_t works." >&4 -else - val="$undef" - set d_socklen; eval $setvar - echo "socklen_t doesn't work. Using int." >&4 -fi diff --git a/U/d_stdstdio.U b/U/d_stdstdio.U deleted file mode 100644 index 4448ba3..0000000 --- a/U/d_stdstdio.U +++ /dev/null @@ -1,30 +0,0 @@ -?RCS: $Id: d_stdstdio.U 1.1 Thu, 20 Jul 2000 17:42:54 -0500 dunemush $ -?RCS: -?RCS: Copyright (c) 1991-1993, Raphael Manfredi -?RCS: -?RCS: You may redistribute only under the terms of the Artistic Licence, -?RCS: as specified in the README file that comes with the distribution. -?RCS: You may reuse parts of this distribution only within the terms of -?RCS: that same Artistic Licence; a copy of which may be found at the root -?RCS: of the source tree for dist 3.0. -?RCS: -?RCS: Original Author: Tye McQueen -?RCS: Actually, now this won't do anything. -?RCS: -?RCS: $Log: d_stdstdio.U,v $ -?RCS: Revision 3.0.1.1 1995/05/12 12:12:11 ram -?RCS: patch54: complete rewrite by Tye McQueen to fit modern systems -?RCS: -?RCS: Revision 3.0 1993/08/18 12:07:31 ram -?RCS: Baseline for dist 3.0 netwide release. -?RCS: -?MAKE:d_stdstdio d_stdiobase stdio_ptr stdio_cnt stdio_base \ - stdio_bufsiz: +ccflags \ - Setvar Findhdr Oldconfig -?MAKE: -pick add $@ %< -?LINT:describe d_stdstdio d_stdiobase stdio_base stdio_bufsiz \ - stdio_cnt stdio_ptr -?LINT:set d_stdstdio d_stdiobase stdio_base stdio_bufsiz \ - stdio_cnt stdio_ptr -: do nothing but prevent the standard stdstdio.U from running - diff --git a/U/d_strchr.U b/U/d_strchr.U deleted file mode 100644 index d458fd4..0000000 --- a/U/d_strchr.U +++ /dev/null @@ -1,109 +0,0 @@ -?RCS: $Id: d_strchr.U 1.1 Thu, 20 Jul 2000 17:42:54 -0500 dunemush $ -?RCS: -?RCS: Copyright (c) 1991-1993, Raphael Manfredi -?RCS: -?RCS: You may redistribute only under the terms of the Artistic Licence, -?RCS: as specified in the README file that comes with the distribution. -?RCS: You may reuse parts of this distribution only within the terms of -?RCS: that same Artistic Licence; a copy of which may be found at the root -?RCS: of the source tree for dist 3.0. -?RCS: -?RCS: $Log: d_strchr.U,v $ -?RCS: Revision 3.0.1.2 1993/10/16 13:49:20 ram -?RCS: patch12: added support for HAS_INDEX -?RCS: patch12: added magic for index() and rindex() -?RCS: -?RCS: Revision 3.0.1.1 1993/09/13 16:05:26 ram -?RCS: patch10: now only defines HAS_STRCHR, no macro remap of index (WAD) -?RCS: -?RCS: Revision 3.0 1993/08/18 12:07:32 ram -?RCS: Baseline for dist 3.0 netwide release. -?RCS: -?MAKE:d_strchr d_index: contains strings Setvar Myread Oldconfig Csym -?MAKE: -pick add $@ %< -?S:d_strchr: -?S: This variable conditionally defines HAS_STRCHR if strchr() and -?S: strrchr() are available for string searching. -?S:. -?S:d_index: -?S: This variable conditionally defines HAS_INDEX if index() and -?S: rindex() are available for string searching. -?S:. -?C:HAS_STRCHR: -?C: This symbol is defined to indicate that the strchr()/strrchr() -?C: functions are available for string searching. If not, try the -?C: index()/rindex() pair. -?C:. -?C:HAS_INDEX: -?C: This symbol is defined to indicate that the index()/rindex() -?C: functions are available for string searching. -?C:. -?H:#$d_strchr HAS_STRCHR /**/ -?H:#$d_index HAS_INDEX /**/ -?H:. -?M:index: HAS_INDEX -?M:#ifndef HAS_INDEX -?M:#ifndef index -?M:#define index strchr -?M:#endif -?M:#endif -?M:. -?M:strchr: HAS_STRCHR -?M:#ifndef HAS_STRCHR -?M:#ifndef strchr -?M:#define strchr index -?M:#endif -?M:#endif -?M:. -?M:rindex: HAS_INDEX -?M:#ifndef HAS_INDEX -?M:#ifndef rindex -?M:#define rindex strrchr -?M:#endif -?M:#endif -?M:. -?M:strrchr: HAS_STRCHR -?M:#ifndef HAS_STRCHR -?M:#ifndef strrchr -?M:#define strrchr rindex -?M:#endif -?M:#endif -?M:. -?T:vali -?LINT:set d_strchr d_index -: index or strchr -echo " " -if set index val -f; eval $csym; $val; then - if set strchr val -f d_strchr; eval $csym; $val; then - if $contains strchr "$strings" >/dev/null 2>&1 ; then -?X: has index, strchr, and strchr in string header - val="$define" - vali="$define" - echo "strchr() and index() found." >&4 - else -?X: has index, strchr, and no strchr in string header - val="$undef" - vali="$define" - echo "index() found." >&4 - fi - else -?X: has only index, no strchr, string header is a moot point - val="$undef" - vali="$define" - echo "index() found." >&4 - fi -else - if set strchr val -f d_strchr; eval $csym; $val; then - val="$define" - vali="$undef" - echo "strchr() found." >&4 - else - echo "No index() or strchr() found!" >&4 - val="$undef" - vali="$undef" - fi -fi -set d_strchr; eval $setvar -val="$vali" -set d_index; eval $setvar - diff --git a/U/d_strcoll.U b/U/d_strcoll.U deleted file mode 100644 index 716a575..0000000 --- a/U/d_strcoll.U +++ /dev/null @@ -1,40 +0,0 @@ -?RCS: $Id: d_strcoll.U 1.3 Tue, 30 Sep 2003 18:01:23 -0500 dunemush $ -?RCS: -?RCS: Copyright (c) 1991-1993, Raphael Manfredi -?RCS: -?RCS: You may redistribute only under the terms of the Artistic Licence, -?RCS: as specified in the README file that comes with the distribution. -?RCS: You may reuse parts of this distribution only within the terms of -?RCS: that same Artistic Licence; a copy of which may be found at the root -?RCS: of the source tree for dist 3.0. -?RCS: -?RCS: Original Author: Andy Dougherty -?RCS: -?RCS: $Log: d_strcoll.U,v $ -?RCS: Revision 3.0.1.1 1994/08/29 16:12:01 ram -?RCS: patch32: created by ADO -?RCS: -?MAKE:d_strcoll: Inlibc -?MAKE: -pick add $@ %< -?S:d_strcoll: -?S: This variable conditionally defines HAS_STRCOLL if strcoll() is -?S: available to compare strings using collating information. -?S:. -?C:HAS_STRCOLL: -?C: This symbol, if defined, indicates that the strcoll routine is -?C: available to compare strings using collating information. -?C:. -?H:#$d_strcoll HAS_STRCOLL /**/ -?H:. -?M:strcoll: HAS_STRCOLL -?M:#ifndef HAS_STRCOLL -?M:#undef strcoll -?M:#define strcoll strcmp -?M:#endif -?M:. -?W:%<:strcoll -?LINT:set d_strcoll -: see if strcoll exists -set strcoll d_strcoll -eval $inlibc - diff --git a/U/d_strxfrm.U b/U/d_strxfrm.U deleted file mode 100644 index 6d41024..0000000 --- a/U/d_strxfrm.U +++ /dev/null @@ -1,40 +0,0 @@ -?RCS: $Id: d_strxfrm.U 1.2 Tue, 20 Nov 2001 17:08:09 -0600 dunemush $ -?RCS: -?RCS: Copyright (c) 1991-1993, Raphael Manfredi -?RCS: -?RCS: You may redistribute only under the terms of the Artistic Licence, -?RCS: as specified in the README file that comes with the distribution. -?RCS: You may reuse parts of this distribution only within the terms of -?RCS: that same Artistic Licence; a copy of which may be found at the root -?RCS: of the source tree for dist 3.0. -?RCS: -?RCS: Original Author: Andy Dougherty -?RCS: -?RCS: $Log: d_strxfrm.U,v $ -?RCS: Revision 3.0.1.1 1994/08/29 16:12:01 ram -?RCS: patch32: created by ADO -?RCS: -?MAKE:d_strxfrm: Inlibc -?MAKE: -pick add $@ %< -?S:d_strxfrm: -?S: This variable conditionally defines HAS_STRXFRM if strxfrm() is -?S: available to transform strings using collating information. -?S:. -?C:HAS_STRXFRM: -?C: This symbol, if defined, indicates that the strxfrm routine is -?C: available to transform strings using collating information. -?C:. -?H:#$d_strxfrm HAS_STRXFRM /**/ -?H:. -?M:strxfrm: HAS_STRXFRM -?M:#if !defined(WIN32) && !defined(HAS_STRXFRM) -?M:#define strncoll strncmp -?M:#define strncasecoll strncasecmp -?M:#define strcasecoll strcasecmp -?M:#endif -?M:. -?LINT:set d_strxfrm -: see if strxfrm exists -set strxfrm d_strxfrm -eval $inlibc - diff --git a/U/d_sysctl.U b/U/d_sysctl.U deleted file mode 100644 index 16b2cb2..0000000 --- a/U/d_sysctl.U +++ /dev/null @@ -1,32 +0,0 @@ -?RCS: -?RCS: -?RCS: -?MAKE:d_sysctl d_sysctlbyname: Inlibc -?MAKE: -pick add $@ %< -?S:d_sysctl: -?S: This variable conditionally defines the HAS_SYSCTL symbol, which -?S: indicates that the sysctl() routine exists. -?S:. -?S:d_sysctlbyname: -?S: This variable conditionally defines the HAS_SYSCTLBYNAME symbol, which -?S: indicates that the sysctlbyname() routine exists. -?S:. -?C:HAS_SYSCTL: -?C: This symbol, if defined, indicates that the sysctl() routine is -?C: available to get some system parameters. -?C:. -?C:HAS_SYSCTLBYNAME: -?C: This symbol, if defined, indicates that the sysctlbyname() routine is -?C: available to get some system parameters. -?C:. -?H:#$d_sysctl HAS_SYSCTL /**/ -?H:#$d_sysctlbyname HAS_SYSCTLBYNAME /**/ -?H:. -?LINT:set d_sysctl d_sysctlbyname -: see if sysctl exists -set sysctl d_sysctl -eval $inlibc -: see if sysctlbyname exists -set sysctlbyname d_sysctlbyname -eval $inlibc - diff --git a/U/d_tcl.U b/U/d_tcl.U deleted file mode 100644 index ed99234..0000000 --- a/U/d_tcl.U +++ /dev/null @@ -1,77 +0,0 @@ -?MAKE:d_tcl i_tcl: Loc test xlibpth libpth Csym Setvar Inhdr libs -?MAKE: -pick add $@ %< -?S:d_tcl: -?S: This variable conditionally defines the TCL symbol, which -?S: indicates to the C program that the tcl library is available. -?S:. -?S:i_tcl: -?S: This variable conditionally defines the I_TCL symbol, which -?S: indicates whether a C program should include -?S:. -?C:HAS_TCL: -?C: This symbol, if defined, indicates that the tcl library is available -?C:. -?C:I_TCL: -?C: This symbol, if defined, indicates that can be included. -?C:. -?H:?%<:/* HAS_TCL: -?H:?%<: * This symbol, if defined, means we have the tcl library -?H:?%<: */ -?H:?%<:#$d_tcl HAS_TCL /**/ -?H:. -?H:?%<:/* I_TCL: -?H:?%<: * This symbol, if defined, means we have the include file -?H:?%<: */ -?H:?%<:#$i_tcl I_TCL /**/ -?H:. -?W:d_tcl:HAS_TCL I_TCL -?LINT:set d_tcl i_tcl -?T:val -: see if tcl exists -echo " " -ok=0 - -if $test -f src/tcl.c -o -f ../src/tcl.c ; then - echo "I'm tickled pink - we have the penn TCL source." >&4 - echo "Let's see if we have TCL." >&4 - -: see if tcl.h can be included - set tcl.h i_tcl - eval $inhdr - if $test $i_tcl = "$define"; then - echo "We have tcl.h, that's a start." >&4 - : see if the tcl library was found earlier - case $libs in - *tcl*) val="$define" - set d_tcl - eval $setvar - echo "We have the TCL library, too." >&4 - ok=1 - ;; - *) echo "Oops, no TCL library. Check your TCL installation." >&4 - ;; - esac - else - echo "I can't find tcl.h. Check your TCL installation." >&4 - fi -fi - -if $test $ok = 0; then - nlibs="" - for l in $libs; do - case $l in - "-ltcl") ;; - "-ld") ;; - *) nlibs="$nlibs$l " ;; - esac - done - libs="$nlibs" - val="$undef" - set d_tcl - eval $setvar - val="$undef" - set i_tcl - eval $setvar -else - echo "TCL will be compiled and included." >&4 -fi diff --git a/U/d_textdomain.U b/U/d_textdomain.U deleted file mode 100644 index 01a923e..0000000 --- a/U/d_textdomain.U +++ /dev/null @@ -1,41 +0,0 @@ -?RCS: $Id: d_textdomain.U 1.2 Wed, 13 Sep 2000 14:49:45 -0500 dunemush $ -?RCS: -?RCS: Copyright (c) 1995, Alan Schwartz -?RCS: -?RCS: You may redistribute only under the terms of the Artistic Licence, -?RCS: as specified in the README file that comes with the distribution. -?RCS: You may reuse parts of this distribution only within the terms of -?RCS: that same Artistic Licence; a copy of which may be found at the root -?RCS: of the source tree for dist 3.0. -?RCS: -?MAKE:d_textdomain: Myread cat cc ccflags rm ldflags libs i_libintl -?MAKE: -pick add $@ %< -?S:d_textdomain: -?S: Defined if textdomain() is available. -?S:. -?C:HAS_TEXTDOMAIN: -?C: Defined if textdomain is available(). -?C:. -?H:#$d_textdomain HAS_TEXTDOMAIN /**/ -?H:. -: check for a new-style definitions -echo " " -$cat >test_textdomain.c < -#endif -int main(int argc, char **argv) { - return (int) textdomain (""); -} -EOCP - -if $cc $ccflags $ldflags -o test_textdomain test_textdomain.c $libs >/dev/null 2>&1 ; then - d_textdomain='define' - echo 'Mabuhay! You seem to have textdomain for translations.' >&4 -else - d_textdomain='undef' - echo "You don't seem to have textdomain. Sayang." >&4 -fi -$rm -f test_textdomain* core - diff --git a/U/d_timelocal.U b/U/d_timelocal.U deleted file mode 100644 index f563d3b..0000000 --- a/U/d_timelocal.U +++ /dev/null @@ -1,22 +0,0 @@ -?RCS: $Id: d_timelocal.U 1.1 Thu, 20 Jul 2000 17:42:54 -0500 dunemush $ -?RCS: -?RCS: Copyright (c) 1995, Alan Schwartz -?RCS: -?RCS: -?MAKE:d_timelocal: Inlibc -?MAKE: -pick add $@ %< -?S:d_timelocal: -?S: This variable conditionally defines the HAS_TIMELOCAL symbol, which -?S: indicates that the timelocal() routine exists. -?S:. -?C:HAS_TIMELOCAL: -?C: This symbol, if defined, indicates that the timelocal() routine is -?C: available. -?C:. -?H:#$d_timelocal HAS_TIMELOCAL /**/ -?H:. -?LINT:set d_timelocal -: see if timelocal exists -set timelocal d_timelocal -eval $inlibc - diff --git a/U/d_toupper.U b/U/d_toupper.U deleted file mode 100644 index 126bf5a..0000000 --- a/U/d_toupper.U +++ /dev/null @@ -1,54 +0,0 @@ -?RCS: $Id: d_toupper.U 1.1 Thu, 20 Jul 2000 17:42:54 -0500 dunemush $ -?RCS: -?RCS: Copyright (c) 1995, Alan Schwartz -?RCS: -?RCS: You may redistribute only under the terms of the Artistic Licence, -?RCS: as specified in the README file that comes with the distribution. -?RCS: You may reuse parts of this distribution only within the terms of -?RCS: that same Artistic Licence; a copy of which may be found at the root -?RCS: of the source tree for dist 3.0. -?RCS: -?MAKE:d_toupper: Myread cat cc ccflags rm ldflags -?MAKE: -pick add $@ %< -?S:d_toupper: -?S: Defined if toupper() can operate safely on any ascii character. -?S:. -?C:HAS_SAFE_TOUPPER: -?C: Defined if toupper() can operate safely on any ascii character. -?C: Some systems only allow toupper() on lower-case ascii chars. -?C:. -?H:#$d_toupper HAS_SAFE_TOUPPER /**/ -?H:. -: check for a safe toupper -echo " " -echo "Checking out your toupper()..." >&4 -$cat >test_toupper.c <<'EOCP' -#include -#include - -int main() { - char c = 'A'; - if (c == toupper(c)) { - printf("define\n"); - } else { - printf("undef\n"); - } - exit(0); -} -EOCP - -if $cc $ccflags $ldflags -o test_toupper test_toupper.c >/dev/null 2>&1 ; then - d_toupper=`./test_toupper` - if test $d_toupper = define ; then - echo "It's safe toupper uppers." >&4 - else - echo "We can't toupper uppers." >&4 - fi -else - $cat <&4 -echo " " - $cat >d_uint32.c < -#$i_stdint I_STDINT -#ifdef I_STDINT -#include -#endif - -int main() -{ - uint32_t a; - a = 2*2*2*2; - a *= a; /* 2^8 */ - a *= a; /* 2^16 */ - a *= a; /* 2^32 */ - a += 1; /* 2^32 + 1 */ - if (a == 1) - printf("ok\n"); - else - printf("not ok\n"); -} -EOCP - -if $cc $ccflags $ldflags d_uint32.c -o d_uint32 $libs >/dev/null 2>&1; then - val=`./d_uint32` - if test $val = "ok" ; then - val="$define" - set d_uint32_t; eval $setvar - echo "You have uint32_t." >&4 - else - val="$undef" - set d_uint32_t; eval $setvar - echo "You don't have uint32_t, hope you're a 32 bit machine." >&4 - fi -else - val="$undef" - set d_uint32_t; eval $setvar - echo "I can't tell if you have uint32_t, hope you're a 32 bit machine." >&4 -fi - -$rm -f d_uint32* - diff --git a/U/d_uptime.U b/U/d_uptime.U deleted file mode 100644 index 79c799a..0000000 --- a/U/d_uptime.U +++ /dev/null @@ -1,47 +0,0 @@ -?RCS: $Id: d_uptime.U 1.1 Thu, 20 Jul 2000 17:42:54 -0500 dunemush $ -?RCS: -?RCS: Copyright (c) 1991-1993, Raphael Manfredi -?RCS: -?RCS: You may redistribute only under the terms of the Artistic Licence, -?RCS: as specified in the README file that comes with the distribution. -?RCS: You may reuse parts of this distribution only within the terms of -?RCS: that same Artistic Licence; a copy of which may be found at the root -?RCS: of the source tree for dist 3.0. -?RCS: -?RCS: $Log: d_uptime.U,v $ -?RCS: Revision 3.0.1.2 1993/10/16 13:49:20 ram -?RCS: patch12: added support for HAS_INDEX -?RCS: patch12: added magic for index() and rindex() -?RCS: -?RCS: Revision 3.0.1.1 1993/09/13 16:05:26 ram -?RCS: patch10: now only defines HAS_STRCHR, no macro remap of index (WAD) -?RCS: -?RCS: Revision 3.0 1993/08/18 12:07:32 ram -?RCS: Baseline for dist 3.0 netwide release. -?RCS: -?MAKE:d_uptime : Setvar Oldconfig Csym uptime test -?MAKE: -pick add $@ %< -?S:d_uptime: -?S: This variable conditionally defines UPTIME_PATH if the uptime -?S: program is available. -?S:. -?C:UPTIME_PATH: -?C: This symbol gives the full path to the uptime(1) program if -?C: it exists on the system. If not, this symbol is undefined. -?C:. -?C:HAS_UPTIME: -?C: This symbol is defined if uptime(1) is available. -?C:. -?H:#$d_uptime HAS_UPTIME /**/ -?H:#define UPTIME_PATH "$uptime" -?H:. -?LINT:set d_uptime -: uptime -echo " " -if $test -x $uptime ; then - val="$define" -else - val="$undef" -fi -set d_uptime; eval $setvar - diff --git a/U/d_urandom.U b/U/d_urandom.U deleted file mode 100644 index 71d6bc8..0000000 --- a/U/d_urandom.U +++ /dev/null @@ -1,31 +0,0 @@ -?RCS: $Id: d_urandom.U 1.1 Tue, 08 Apr 2003 22:02:39 -0500 dunemush $ -?RCS: -?RCS: Copyright (c) 2002, Shawn Wagner -?RCS: -?RCS: You may redistribute only under the terms of the Artistic Licence, -?RCS: as specified in the README file that comes with the distribution. -?RCS: You may reuse parts of this distribution only within the terms of -?RCS: that same Artistic Licence; a copy of which may be found at the root -?RCS: of the source tree for dist 3.0. -?RCS: -?MAKE:d_urandom : Setvar Oldconfig Csym test -?MAKE: -pick add $@ %< -?S:d_urandom: -?S: This variable conditionally defines HAS_DEV_URANDOM if the /dev/urandom -?S: special file is available. -?S:. -?C:HAS_DEV_URANDOM: -?C: This symbol is defined if /dev/urandom is available. -?C:. -?H:#$d_urandom HAS_DEV_URANDOM /**/ -?H:. -?LINT:set d_urandom -: see if /dev/urandom is present -echo " " -if $test -c /dev/urandom ; then - val="$define" -else - val="$undef" -fi -set d_urandom; eval $setvar - diff --git a/U/d_uwait.U b/U/d_uwait.U deleted file mode 100644 index 80c8bd3..0000000 --- a/U/d_uwait.U +++ /dev/null @@ -1,126 +0,0 @@ -?RCS: $Id: d_uwait.U 1.2 Wed, 09 Aug 2000 14:09:22 -0500 dunemush $ -?RCS: -?RCS: Copyright (c) 1991-1993, Raphael Manfredi -?RCS: -?RCS: You may redistribute only under the terms of the Artistic Licence, -?RCS: as specified in the README file that comes with the distribution. -?RCS: You may reuse parts of this distribution only within the terms of -?RCS: that same Artistic Licence; a copy of which may be found at the root -?RCS: of the source tree for dist 3.0. -?RCS: -?RCS: $Log: d_uwait.U,v $ -?RCS: Revision 3.0.1.1 1994/01/24 14:10:49 ram -?RCS: patch16: added knowledge about wait3() -?RCS: patch16: revised 'union wait' look-up algorithm -?RCS: patch16: fixed make dependency line accordingly -?RCS: -?RCS: Revision 3.0 1993/08/18 12:07:54 ram -?RCS: Baseline for dist 3.0 netwide release. -?RCS: -?MAKE:d_uwait d_uwait3: cat contains cppstdin cppminus +cppflags rm \ - Setvar Findhdr -?MAKE: -pick add $@ %< -?S:d_uwait: -?S: This symbol conditionally defines UNION_WAIT which indicates to the C -?S: program that argument for the wait() system call should be declared as -?S: 'union wait status' instead of 'int status'. -?S:. -?S:d_uwait3: -?S: This symbol conditionally defines UNION_WAIT3 which indicates to the C -?S: program that the first argument for the wait3() system call should be -?S: declared as 'union wait status' instead of 'int status'. -?S:. -?C:UNION_WAIT: -?C: This symbol if defined indicates to the C program that the argument -?C: for the wait() system call should be declared as 'union wait status' -?C: instead of 'int status'. You probably need to include -?C: in the former case (see I_SYSWAIT). -?C:. -?C:UNION_WAIT3: -?C: This symbol if defined indicates to the C program that the first argument -?C: for the wait3() system call should be declared as 'union wait status' -?C: instead of 'int status'. You probably need to include -?C: in the former case (see I_SYS_WAIT). It seems safe to assume that the -?C: same rule applies to the second parameter of wait4(). -?C:. -?H:#$d_uwait UNION_WAIT /**/ -?H:#$d_uwait3 UNION_WAIT3 /**/ -?H:. -?T:val2 flags f also -?LINT:set d_uwait d_uwait3 -: see if union wait is available -echo " " -?X: -?X: Unfortunately, we can't just grep for "union wait" because -?X: some weird systems (did I hear HP-UX?) define union wait only when _BSD -?X: is defined. The same thing happens on OSF/1, who is pushing weirdness to -?X: its limits by requiring wait() to use (int *) but wait3() to use -?X: (union wait *), unless _BSD is defined and -lbsd is used, in which case -?X: wait() also expects (union wait *). Aaargh!!--RAM -?X: -set X $cppflags -shift -flags='' -also='' -for f in $*; do - case "$f" in - *NO_PROTO*) ;; - *) flags="$flags $f";; - esac -done -xxx="`./findhdr sys/wait.h`" -case "x$xxx" in -x) xxx=/dev/null -esac -$cat "$xxx" | $cppstdin $flags $cppminus >wait.out 2>/dev/null -if $contains 'union.*wait.*{' wait.out >/dev/null 2>&1 ; then - echo "Looks like your knows about 'union wait'..." >&4 - val="$define" -@if UNION_WAIT - also='also ' - if $contains 'extern.*wait[ ]*([ ]*int' wait.out >/dev/null 2>&1 - then - echo "But wait() seems to expect an 'int' pointer (POSIX way)." >&4 - val="$undef" - also='' - elif $contains 'extern.*wait[ ]*([ ]*union' wait.out >/dev/null 2>&1 - then - echo "And indeed wait() expects an 'union wait' pointer (BSD way)." >&4 - else - echo "So we'll use that for wait()." >&4 - fi -@end -@if UNION_WAIT3 || d_uwait3 - val2="$define" -@end -@if UNION_WAIT3 - if $contains 'extern.*wait3[ ]*([ ]*int' wait.out >/dev/null 2>&1 - then - echo "However wait3() seems to expect an 'int' pointer, weird." >&4 - val2="$undef" - elif $contains 'extern.*wait3[ ]*([ ]*union' wait.out >/dev/null 2>&1 - then - echo "And wait3() ${also}expects an 'union wait' pointer, fine." >&4 - else - echo "As expected, wait3() ${also}uses an 'union wait' pointer." >&4 - fi -@end -else - echo "No trace of 'union wait' in ..." >&4 - val="$undef" -@if UNION_WAIT && UNION_WAIT3 - echo "Both wait() and wait3() will use a plain 'int' pointer then." >&4 -@elsif UNION_WAIT - echo "Your wait() should be happy with a plain 'int' pointer." >&4 -@elsif UNION_WAIT3 - echo "Your wait3() should be happy with a plain 'int' pointer." >&4 -@end -fi -set d_uwait -eval $setvar -@if UNION_WAIT3 || d_uwait3 -val="$val2"; set d_uwait3 -eval $setvar -@end -$rm -f wait.out - diff --git a/U/d_vsnprintf.U b/U/d_vsnprintf.U deleted file mode 100644 index 2f98cba..0000000 --- a/U/d_vsnprintf.U +++ /dev/null @@ -1,41 +0,0 @@ -?RCS: $Id: d_vsnprintf.U 1.2 Sat, 30 Jun 2001 08:59:12 -0500 dunemush $ -?RCS: -?RCS: Copyright (c) 1991-1993, Raphael Manfredi -?RCS: -?RCS: You may redistribute only under the terms of the Artistic Licence, -?RCS: as specified in the README file that comes with the distribution. -?RCS: You may reuse parts of this distribution only within the terms of -?RCS: that same Artistic Licence; a copy of which may be found at the root -?RCS: of the source tree for dist 3.0. -?RCS: -?RCS: $Log: d_vsnprintf.U,v $ -?RCS: Revision 3.0 1993/08/18 12:07:59 ram -?RCS: Baseline for dist 3.0 netwide release. -?RCS: -?MAKE:d_vsnprintf: Guess cat +cc +ccflags Csym Setvar -?MAKE: -pick add $@ %< -?S:d_vsnprintf: -?S: This variable conditionally defines the HAS_VSNPRINTF symbol, which -?S: indicates to the C program that the vsnprintf() routine is available -?S: to printf with a pointer to an argument list. -?S:. -?C:HAS_VSNPRINTF: -?C: This symbol, if defined, indicates that the vsnprintf routine is -?C: available to printf with a pointer to an argument list. If not, you -?C: may need to write your own, probably in terms of _doprnt(). -?C:. -?H:#$d_vsnprintf HAS_VSNPRINTF /**/ -?H:. -?LINT:set d_vsnprintf -: see if vsnprintf exists -echo " " -if set vsnprintf val -f d_vsnprintf; eval $csym; $val; then - echo 'vsnprintf() found.' >&4 - val="$define" -else - echo 'vsnprintf() NOT found.' >&4 - val="$undef" -fi -set d_vsnprintf -eval $setvar - diff --git a/U/i_arpanameser.U b/U/i_arpanameser.U deleted file mode 100644 index cf293fb..0000000 --- a/U/i_arpanameser.U +++ /dev/null @@ -1,31 +0,0 @@ -?RCS: $Id: i_arpanameser.U 1.1 Thu, 01 Feb 2001 14:47:02 -0600 dunemush $ -?RCS: -?RCS: Copyright (c) 1991-1993, Raphael Manfredi -?RCS: -?RCS: You may redistribute only under the terms of the Artistic Licence, -?RCS: as specified in the README file that comes with the distribution. -?RCS: You may reuse parts of this distribution only within the terms of -?RCS: that same Artistic Licence; a copy of which may be found at the root -?RCS: of the source tree for dist 3.0. -?RCS: -?RCS: $Log: i_arpanameser.U,v $ -?RCS: Revision 3.0 1993/08/18 12:08:15 ram -?RCS: Baseline for dist 3.0 netwide release. -?RCS: -?MAKE:i_arpanameser: Inhdr -?MAKE: -pick add $@ %< -?S:i_arpanameser: -?S: This variable conditionally defines the I_ARPA_NAMESER symbol, -?S: and indicates whether a C program should include . -?S:. -?C:I_ARPA_NAMESER: -?C: This symbol, if defined, indicates to the C program that it should -?C: include to get nameser_addr and friends declarations. -?C:. -?H:#$i_arpanameser I_ARPA_NAMESER /**/ -?H:. -?LINT:set i_arpanameser -: see if arpa/nameser.h has to be included -set arpa/nameser.h i_arpanameser -eval $inhdr - diff --git a/U/i_errno.U b/U/i_errno.U deleted file mode 100644 index 0f4e2da..0000000 --- a/U/i_errno.U +++ /dev/null @@ -1,46 +0,0 @@ -?RCS: $Id: i_errno.U 1.1 Thu, 20 Jul 2000 17:42:54 -0500 dunemush $ -?RCS: -?RCS: Copyright (c) 1991-1993, Raphael Manfredi -?RCS: -?RCS: You may redistribute only under the terms of the Artistic Licence, -?RCS: as specified in the README file that comes with the distribution. -?RCS: You may reuse parts of this distribution only within the terms of -?RCS: that same Artistic Licence; a copy of which may be found at the root -?RCS: of the source tree for dist 3.0. -?RCS: -?RCS: $Log: i_errno.U,v $ -?RCS: Revision 3.0 1993/08/18 12:08:34 ram -?RCS: Baseline for dist 3.0 netwide release. -?RCS: -?X: -?X: Look whether needs to be included -?X: -?MAKE:i_errno i_syserrno: Inhdr -?MAKE: -pick add $@ %< -?S:i_errno: -?S: This variable conditionally defines the I_ERRNO symbol, -?S: and indicates whether a C program can include . -?S:. -?S:i_syserrno: -?S: This variable conditionally defines the I_SYS_ERRNO symbol, -?S: and indicates whether a C program can include . -?S:. -?C:I_ERRNO: -?C: This symbol, if defined, indicates to the C program that it can -?C: include . -?C:. -?C:I_SYS_ERRNO: -?C: This symbol, if defined, indicates to the C program that it can -?C: include . -?C:. -?H:#$i_errno I_ERRNO /**/ -?H:. -?H:#$i_syserrno I_SYS_ERRNO /**/ -?H:. -?LINT:set i_errno i_syserrno -: see if errno.h can be included -set errno.h i_errno -eval $inhdr -: see if sys/errno.h can be included -set sys/errno.h i_syserrno -eval $inhdr diff --git a/U/i_libintl.U b/U/i_libintl.U deleted file mode 100644 index a9b6a98..0000000 --- a/U/i_libintl.U +++ /dev/null @@ -1,33 +0,0 @@ -?RCS: $Id: i_libintl.U 1.1 Thu, 20 Jul 2000 17:42:54 -0500 dunemush $ -?RCS: -?RCS: Copyright (c) 1991-1993, Raphael Manfredi -?RCS: -?RCS: You may redistribute only under the terms of the Artistic Licence, -?RCS: as specified in the README file that comes with the distribution. -?RCS: You may reuse parts of this distribution only within the terms of -?RCS: that same Artistic Licence; a copy of which may be found at the root -?RCS: of the source tree for dist 3.0. -?RCS: -?RCS: $Log: i_libintl.U,v $ -?RCS: Revision 3.0 1993/08/18 12:08:34 ram -?RCS: Baseline for dist 3.0 netwide release. -?RCS: -?X: -?X: Look whether can be included -?X: -?MAKE:i_libintl: Inhdr -?MAKE: -pick add $@ %< -?S:i_libintl: -?S: This variable conditionally defines the I_LIBINTL symbol, -?S: and indicates whether a C program can include . -?S:. -?C:I_LIBINTL: -?C: This symbol, if defined, indicates to the C program that it can -?C: include . -?C:. -?H:#$i_libintl I_LIBINTL /**/ -?H:. -?LINT:set i_libintl -: see if libintl.h can be included -set libintl.h i_libintl -eval $inhdr diff --git a/U/i_memory.U b/U/i_memory.U deleted file mode 100644 index f1fe84e..0000000 --- a/U/i_memory.U +++ /dev/null @@ -1,68 +0,0 @@ -?RCS: $Id: i_memory.U 1.1 Thu, 20 Jul 2000 17:42:54 -0500 dunemush $ -?RCS: -?RCS: Copyright (c) 1991-1993, Raphael Manfredi -?RCS: -?RCS: You may redistribute only under the terms of the Artistic Licence, -?RCS: as specified in the README file that comes with the distribution. -?RCS: You may reuse parts of this distribution only within the terms of -?RCS: that same Artistic Licence; a copy of which may be found at the root -?RCS: of the source tree for dist 3.0. -?RCS: -?RCS: $Log: i_memory.U,v $ -?RCS: Revision 1.2 1997/11/25 22:07:30 popiel -?RCS: , -?RCS: -?RCS: Revision 3.0.1.3 1994/06/20 07:01:55 ram -?RCS: patch30: cosmetic changes -?RCS: -?RCS: Revision 3.0.1.2 1994/05/13 15:23:56 ram -?RCS: patch27: modified to avoid spurious Whoa warnings (ADO) -?RCS: -?RCS: Revision 3.0.1.1 1994/05/06 15:02:25 ram -?RCS: patch23: avoid conflicts with -?RCS: -?RCS: Revision 3.0 1993/08/18 12:08:22 ram -?RCS: Baseline for dist 3.0 netwide release. -?RCS: -?MAKE:i_memory: Inhdr strings cppstdin cppflags cppminus contains rm Setvar -?MAKE: -pick add $@ %< -?S:i_memory: -?S: This variable conditionally defines the I_MEMORY symbol, and indicates -?S: whether a C program should include . -?S:. -?C:I_MEMORY: -?C: This symbol, if defined, indicates to the C program that it should -?C: include . -?C:. -?H:#$i_memory I_MEMORY /**/ -?H:. -?LINT:set i_memory -?X: -?X: Unfortunately, the definitions of memory functions sometimes -?X: conflict with those in . We'll assume that if -?X: contains memcpy, then we don't need memory.h -?X: -: see if memory.h is available. -val='' -set memory.h val -eval $inhdr - -: See if it conflicts with string.h -case "$val" in -$define) - case "$strings" in - '') ;; - *) - $cppstdin $cppflags $cppminus < "$strings" > mem.h - if $contains 'memcpy' mem.h >/dev/null 2>&1; then - echo " " - echo "We won't be including ." - val="$undef" - fi - $rm -f mem.h - ;; - esac -esac -set i_memory -eval $setvar - diff --git a/U/i_netdb.U b/U/i_netdb.U deleted file mode 100644 index 41f7ef7..0000000 --- a/U/i_netdb.U +++ /dev/null @@ -1,33 +0,0 @@ -?RCS: $Id: i_netdb.U 1.1 Mon, 26 Mar 2001 15:51:56 -0600 dunemush $ -?RCS: -?RCS: Copyright (c) 1991-1993, Raphael Manfredi -?RCS: -?RCS: You may redistribute only under the terms of the Artistic Licence, -?RCS: as specified in the README file that comes with the distribution. -?RCS: You may reuse parts of this distribution only within the terms of -?RCS: that same Artistic Licence; a copy of which may be found at the root -?RCS: of the source tree for dist 3.0. -?RCS: -?RCS: $Log: i_netdb.U,v $ -?RCS: Revision 3.0 1993/08/18 12:08:34 ram -?RCS: Baseline for dist 3.0 netwide release. -?RCS: -?X: -?X: Look whether needs to be included -?X: -?MAKE:i_netdb: Inhdr -?MAKE: -pick add $@ %< -?S:i_netdb: -?S: This variable conditionally defines the I_NETDB symbol, -?S: and indicates whether a C program can include . -?S:. -?C:I_NETDB: -?C: This symbol, if defined, indicates to the C program that it can -?C: include . -?C:. -?H:#$i_netdb I_NETDB /**/ -?H:. -?LINT:set i_netdb -: see if netdb.h can be included -set netdb.h i_netdb -eval $inhdr diff --git a/U/i_nitcp.U b/U/i_nitcp.U deleted file mode 100644 index 1b13b82..0000000 --- a/U/i_nitcp.U +++ /dev/null @@ -1,34 +0,0 @@ -?RCS: $Id$ -?RCS: -?RCS: Copyright (c) 1991-1993, Raphael Manfredi -?RCS: -?RCS: You may redistribute only under the terms of the Artistic Licence, -?RCS: as specified in the README file that comes with the distribution. -?RCS: You may reuse parts of this distribution only within the terms of -?RCS: that same Artistic Licence; a copy of which may be found at the root -?RCS: of the source tree for dist 3.0. -?RCS: -?RCS: $Log: i_nitcp.U,v $ -?RCS: Revision 3.0 1993/08/18 12:08:24 ram -?RCS: Baseline for dist 3.0 netwide release. -?RCS: -?X: -?X: This unit looks wether is available or not -?X: -?MAKE:i_nitcp: Inhdr -?MAKE: -pick add $@ %< -?S:i_nitcp: -?S: This variable conditionally defines I_NETINET_TCP, which indicates -?S: to the C program that it should include . -?S:. -?C:I_NETINET_TCP: -?C: This symbol, if defined, indicates to the C program that it should -?C: include . -?C:. -?H:#$i_nitcp I_NETINET_TCP /**/ -?H:. -?LINT:set i_nitcp -: see if this is a netinet/tcp.h system -set netinet/tcp.h i_nitcp -eval $inhdr - diff --git a/U/i_nl_types.U b/U/i_nl_types.U deleted file mode 100644 index 8a9a741..0000000 --- a/U/i_nl_types.U +++ /dev/null @@ -1,33 +0,0 @@ -?RCS: $Id: i_nl_types.U 1.1 Thu, 20 Jul 2000 17:42:54 -0500 dunemush $ -?RCS: -?RCS: Copyright (c) 1991-1993, Raphael Manfredi -?RCS: -?RCS: You may redistribute only under the terms of the Artistic Licence, -?RCS: as specified in the README file that comes with the distribution. -?RCS: You may reuse parts of this distribution only within the terms of -?RCS: that same Artistic Licence; a copy of which may be found at the root -?RCS: of the source tree for dist 3.0. -?RCS: -?RCS: $Log: i_nl_types.U,v $ -?RCS: Revision 3.0 1993/08/18 12:08:34 ram -?RCS: Baseline for dist 3.0 netwide release. -?RCS: -?X: -?X: Look whether can be included -?X: -?MAKE:i_nl_types: Inhdr -?MAKE: -pick add $@ %< -?S:i_nl_types: -?S: This variable conditionally defines the I_NL_TYPES symbol, -?S: and indicates whether a C program can include . -?S:. -?C:I_NL_TYPES: -?C: This symbol, if defined, indicates to the C program that it can -?C: include . -?C:. -?H:#$i_nl_types I_NL_TYPES /**/ -?H:. -?LINT:set i_nl_types -: see if nl_types.h can be included -set nl_types.h i_nl_types -eval $inhdr diff --git a/U/i_setjmp.U b/U/i_setjmp.U deleted file mode 100644 index e62d95c..0000000 --- a/U/i_setjmp.U +++ /dev/null @@ -1,31 +0,0 @@ -?RCS: $Id: i_setjmp.U 1.1 Wed, 29 Nov 2000 11:35:38 -0600 dunemush $ -?RCS: -?RCS: Copyright (c) 200 Shawn Wagner -?RCS: -?RCS: You may redistribute only under the terms of the Artistic Licence, -?RCS: as specified in the README file that comes with the distribution. -?RCS: You may reuse parts of this distribution only within the terms of -?RCS: that same Artistic Licence; a copy of which may be found at the root -?RCS: of the source tree for dist 3.0. -?RCS: -?RCS: -?X: -?X: Look whether can be included and setjmp/longjmp work -?X: the way we expect. -?X: -?MAKE:i_setjmp: Inhdr -?MAKE: -pick add $@ %< -?S:i_setjmp: -?S: This variable conditionally defines the I_SETJMP symbol, -?S: and indicates wether or not we have a working setjmp/longjmp. -?S:. -?C:I_SETJMP: -?C: This symbol, if defined, indicates to the C program that it can -?C: include and have things work right. -?C:. -?H:#$i_setjmp I_SETJMP /**/ -?H:. -?LINT:set i_setjmp -: see if setjmp.h can be included -set setjmp.h i_setjmp -eval $inhdr diff --git a/U/i_stdint.U b/U/i_stdint.U deleted file mode 100644 index 31dde7c..0000000 --- a/U/i_stdint.U +++ /dev/null @@ -1,32 +0,0 @@ -?RCS: $Id$ -?RCS: -?RCS: Copyright (c) 1991-1993, Raphael Manfredi -?RCS: -?RCS: You may redistribute only under the terms of the Artistic Licence, -?RCS: as specified in the README file that comes with the distribution. -?RCS: You may reuse parts of this distribution only within the terms of -?RCS: that same Artistic Licence; a copy of which may be found at the root -?RCS: of the source tree for dist 3.0. -?RCS: -?RCS: -?MAKE:i_stdint: test Inlibc Cppsym Guess Setvar Findhdr -?MAKE: -pick add $@ %< -?S:i_stdint: -?S: This variable conditionally defines the I_STDINT symbol, which -?S: indicates to the C program that it should include . -?S:. -?C:I_STDINT: -?C: This symbol, if defined, indicates that the program should include -?C: . -?C:. -?H:#$i_stdint I_STDINT /**/ -?H:. -?LINT:set i_stdint -: see if this is a stdint system -val="$undef" -if $test "`./findhdr stdint.h`"; then - val="$define" - echo " found." >&4 -fi -echo " " -set i_stdint; eval $setvar diff --git a/U/i_sysioctl.U b/U/i_sysioctl.U deleted file mode 100644 index 3643214..0000000 --- a/U/i_sysioctl.U +++ /dev/null @@ -1,202 +0,0 @@ -?RCS: $Id: i_sysioctl.U 1.1 Thu, 20 Jul 2000 17:42:54 -0500 dunemush $ -?RCS: -?RCS: Copyright (c) 1991-1993, Raphael Manfredi -?RCS: -?RCS: You may redistribute only under the terms of the Artistic Licence, -?RCS: as specified in the README file that comes with the distribution. -?RCS: You may reuse parts of this distribution only within the terms of -?RCS: that same Artistic Licence; a copy of which may be found at the root -?RCS: of the source tree for dist 3.0. -?RCS: -?RCS: $Log: i_sysioctl.U,v $ -?RCS: Revision 3.0.1.2 1994/05/06 15:04:57 ram -?RCS: patch23: added knowledge for (WED) -?RCS: patch23: optimized amount of findhdr calls -?RCS: -?RCS: Revision 3.0.1.1 1993/11/10 17:36:09 ram -?RCS: patch14: now use a compiler check for TIOCNOTTY because of HP-UX 9.x -?RCS: -?RCS: Revision 3.0 1993/08/18 12:08:32 ram -?RCS: Baseline for dist 3.0 netwide release. -?RCS: -?MAKE:i_sysioctl i_bsdioctl i_sysfilio i_syssockio d_voidtty: test contains \ - cat i_termio i_termios i_sgtty Setvar Findhdr +cc rm Inhdr -?MAKE: -pick add $@ %< -?S:i_sysioctl: -?S: This variable conditionally defines the I_SYS_IOCTL symbol, which -?S: indicates to the C program that exists and should -?S: be included. -?S:. -?S:i_sysfilio: -?S: This variable conditionally defines the I_SYS_FILIO symbol, which -?S: indicates to the C program that exists and should -?S: be included in preference to . -?S:. -?S:i_bsdioctl: -?S: This variable conditionally defines the I_SYS_BSDIOCTL symbol, which -?S: indicates to the C program that exists and should -?S: be included. -?S:. -?S:i_syssockio: -?S: This variable conditionally defines I_SYS_SOCKIO to indicate to the -?S: C program that socket ioctl codes may be found in -?S: instead of . -?S:. -?S:d_voidtty: -?S: This variable conditionally defines USE_IOCNOTTY to indicate that the -?S: ioctl() call with TIOCNOTTY should be used to void tty association. -?S: Otherwise (on USG probably), it is enough to close the standard file -?S: decriptors and do a setpgrp(). -?S:. -?C:I_SYS_IOCTL (I_SYSIOCTL): -?C: This symbol, if defined, indicates that exists and should -?C: be included. Otherwise, include or . -?C:. -?C:I_SYS_FILIO: -?C: This symbol, if defined, indicates that exists and -?C: should be included instead of . -?C:. -?C:I_SYS_BSDIOCTL (I_BSDIOCTL): -?C: This symbol, if defined, indicates that exists and should -?C: be included. Otherwise, try . This is primarly intended for -?C: definitions of sockets options, like SIOCATMARK. -?C:. -?C:I_SYS_SOCKIO (I_SYSSOCKIO): -?C: This symbol, if defined, indicates the should be included -?C: to get socket ioctl options, like SIOCATMARK. -?C:. -?C:USE_TIOCNOTTY (VOIDTTY): -?C: This symbol, if defined indicate to the C program that the ioctl() -?C: call with TIOCNOTTY should be used to void tty association. -?C: Otherwise (on USG probably), it is enough to close the standard file -?C: decriptors and do a setpgrp(). -?C:. -?H:#$i_sysioctl I_SYS_IOCTL /**/ -?H:#$i_sysfilio I_SYS_FILIO /**/ -?H:#$i_bsdioctl I_SYS_BSDIOCTL /**/ -?H:#$i_syssockio I_SYS_SOCKIO /**/ -?H:#$d_voidtty USE_TIOCNOTTY /**/ -?H:. -?T:xxx -: see if ioctl defs are in sgtty, termio, sys/filio or sys/ioctl -?LINT:set i_sysfilio -set sys/filio.h i_sysfilio -eval $inhdr -echo " " -if $test "`./findhdr sys/ioctl.h`"; then - val="$define" - echo ' found.' >&4 -else - val="$undef" - if $test $i_sysfilio = "$define"; then - echo ' NOT found.' >&4 - else - $test $i_sgtty = "$define" && xxx="sgtty.h" - $test $i_termio = "$define" && xxx="termio.h" - $test $i_termios = "$define" && xxx="termios.h" -echo "No found, assuming ioctl args are defined in <$xxx>." >&4 - fi -fi -?LINT:set i_sysioctl -set i_sysioctl -eval $setvar - -@if I_BSDIOCTL || i_bsdioctl -?X: -?X: The only machine I know where this inclusion was necessary is a -?X: BULL DPX 5000 (a French machine). -?X: -: see if socket ioctl defs are in sys/bsdioctl or sys/ioctl -echo " " -xxx="`./findhdr sys/bsdioctl.h`" -if $test "$xxx"; then - if $contains SIOCATMARK $xxx >/dev/null 2>&1; then - val="$define" - echo "You have socket ioctls defined in ." >&4 - else - val="$undef" - echo "No socket ioctls found in ." >&4 - fi -else - val="$undef" - echo " not found, but that's ok." >&4 -fi -?LINT:set i_bsdioctl -set i_bsdioctl -eval $setvar - -@end -@if I_SYSSOCKIO || i_syssockio -: see if socket ioctl defs are in sys/sockio.h -echo " " -xxx="`./findhdr sys/sockio.h`" -if $test "$xxx"; then - if $contains SIOCATMARK $xxx >/dev/null 2>&1; then - val="$define" - echo "You have socket ioctls defined in ." >&4 - else - val="$undef" - echo "No socket ioctls found in ." >&4 - fi -else - val="$undef" -@if I_BSDIOCTL - case "$i_bsdioctl" in - "$define") $cat < not found, using ioctls from . -EOM - ;; - *) $cat < not found, assuming socket ioctls are in . -EOM - ;; - esac -@else - $cat < not found, assuming socket ioctls are in . -EOM -@end -fi -?LINT:set i_syssockio -set i_syssockio -eval $setvar - -@end -@if VOIDTTY || d_voidtty -: check how to void tty association -echo " " -case "$i_sysioctl" in -"$define") xxx='sys/ioctl.h';; -?X: otherwise $xxx was set during the determination of i_sysioctl, above. -esac -?X: -?X: Can't use $contains here since HP-UX 9.x has TIOCNOTTY between a pair -?X: of #ifdef/#endif and is never actually defined. Oh well... -?X: -$cat > tcio.c < /* Just in case */ -#include <$xxx> - -int main() -{ -#ifdef TIOCNOTTY - exit(0); -#else - exit(1); -#endif -} -EOM -if ($cc -o tcio tcio.c && ./tcio) >/dev/null 2>&1; then - val="$define" - echo "TIOCNOTTY found in <$xxx>." >&4 - echo "Using ioctl() call on /dev/tty to void tty association." >&4 -else - val="$undef" - echo "Closing standard file descriptors should void tty association." >&4 -fi -?LINT:set d_voidtty -set d_voidtty -eval $setvar -$rm -f tcio tcio.? core - -@end diff --git a/U/i_syspage.U b/U/i_syspage.U deleted file mode 100644 index b348b84..0000000 --- a/U/i_syspage.U +++ /dev/null @@ -1,34 +0,0 @@ -?RCS: $Id: i_syspage.U 1.1 Thu, 20 Jul 2000 17:42:54 -0500 dunemush $ -?RCS: -?RCS: Copyright (c) 1991-1993, Raphael Manfredi -?RCS: -?RCS: You may redistribute only under the terms of the Artistic Licence, -?RCS: as specified in the README file that comes with the distribution. -?RCS: You may reuse parts of this distribution only within the terms of -?RCS: that same Artistic Licence; a copy of which may be found at the root -?RCS: of the source tree for dist 3.0. -?RCS: -?RCS: $Log: i_syspage.U,v $ -?RCS: Revision 3.0 1993/08/18 12:08:34 ram -?RCS: Baseline for dist 3.0 netwide release. -?RCS: -?X: -?X: Look whether needs to be included -?X: -?MAKE:i_syspage: Inhdr -?MAKE: -pick add $@ %< -?S:i_syspage: -?S: This variable conditionally defines the I_SYS_PAGE symbol, -?S: and indicates whether a C program should include . -?S:. -?C:I_SYS_PAGE (I_SYSPAGE): -?C: This symbol, if defined, indicates to the C program that it should -?C: include . -?C:. -?H:#$i_syspage I_SYS_PAGE /**/ -?H:. -?LINT:set i_syspage -: see if sys/page.h has to be included -set sys/page.h i_syspage -eval $inhdr - diff --git a/U/i_sysvlimit.U b/U/i_sysvlimit.U deleted file mode 100644 index 9de3131..0000000 --- a/U/i_sysvlimit.U +++ /dev/null @@ -1,34 +0,0 @@ -?RCS: $Id: i_sysvlimit.U 1.1 Thu, 20 Jul 2000 17:42:54 -0500 dunemush $ -?RCS: -?RCS: Copyright (c) 1991-1993, Raphael Manfredi -?RCS: -?RCS: You may redistribute only under the terms of the Artistic Licence, -?RCS: as specified in the README file that comes with the distribution. -?RCS: You may reuse parts of this distribution only within the terms of -?RCS: that same Artistic Licence; a copy of which may be found at the root -?RCS: of the source tree for dist 3.0. -?RCS: -?RCS: $Log: i_sysvlimit.U,v $ -?RCS: Revision 3.0 1993/08/18 12:08:34 ram -?RCS: Baseline for dist 3.0 netwide release. -?RCS: -?X: -?X: Look wether needs to be included -?X: -?MAKE:i_sysvlimit: Inhdr -?MAKE: -pick add $@ %< -?S:i_sysvlimit: -?S: This variable conditionally defines the I_SYS_VLIMIT symbol, -?S: and indicates whether a C program should include . -?S:. -?C:I_SYS_VLIMIT (I_SYSVLIMIT): -?C: This symbol, if defined, indicates to the C program that it should -?C: include . -?C:. -?H:#$i_sysvlimit I_SYS_VLIMIT /**/ -?H:. -?LINT:set i_sysvlimit -: see if sys/vlimit.h has to be included -set sys/vlimit.h i_sysvlimit -eval $inhdr - diff --git a/U/i_termio.U b/U/i_termio.U deleted file mode 100644 index 1259aad..0000000 --- a/U/i_termio.U +++ /dev/null @@ -1,123 +0,0 @@ -?RCS: $Id: i_termio.U 1.1 Thu, 20 Jul 2000 17:42:54 -0500 dunemush $ -?RCS: -?RCS: Copyright (c) 1991-1993, Raphael Manfredi -?RCS: -?RCS: You may redistribute only under the terms of the Artistic Licence, -?RCS: as specified in the README file that comes with the distribution. -?RCS: You may reuse parts of this distribution only within the terms of -?RCS: that same Artistic Licence; a copy of which may be found at the root -?RCS: of the source tree for dist 3.0. -?RCS: -?RCS: $Log: i_termio.U,v $ -?RCS: Revision 3.0.1.4 1994/10/29 16:20:54 ram -?RCS: patch36: call ./usg and ./Cppsym explicitely instead of relying on PATH -?RCS: -?RCS: Revision 3.0.1.3 1994/08/29 16:26:38 ram -?RCS: patch32: don't include all threee I_* symbols in config.h -?RCS: patch32: (had forgotten to undo this part last time) -?RCS: -?RCS: Revision 3.0.1.2 1994/05/13 15:25:03 ram -?RCS: patch27: undone ADO's fix in previous patch since it was useless -?RCS: -?RCS: Revision 3.0.1.1 1994/05/06 15:05:23 ram -?RCS: patch23: now include all three defines in config.h (ADO) -?RCS: -?RCS: Revision 3.0 1993/08/18 12:08:44 ram -?RCS: Baseline for dist 3.0 netwide release. -?RCS: -?MAKE:i_termio i_sgtty i_termios: test Inlibc Cppsym Guess Setvar Findhdr -?MAKE: -pick add $@ %< -?S:i_termio: -?S: This variable conditionally defines the I_TERMIO symbol, which -?S: indicates to the C program that it should include rather -?S: than . -?S:. -?S:i_termios: -?S: This variable conditionally defines the I_TERMIOS symbol, which -?S: indicates to the C program that the POSIX file is -?S: to be included. -?S:. -?S:i_sgtty: -?S: This variable conditionally defines the I_SGTTY symbol, which -?S: indicates to the C program that it should include rather -?S: than . -?S:. -?C:I_TERMIO: -?C: This symbol, if defined, indicates that the program should include -?C: rather than . There are also differences in -?C: the ioctl() calls that depend on the value of this symbol. -?C:. -?C:I_TERMIOS: -?C: This symbol, if defined, indicates that the program should include -?C: the POSIX termios.h rather than sgtty.h or termio.h. -?C: There are also differences in the ioctl() calls that depend on the -?C: value of this symbol. -?C:. -?C:I_SGTTY: -?C: This symbol, if defined, indicates that the program should include -?C: rather than . There are also differences in -?C: the ioctl() calls that depend on the value of this symbol. -?C:. -?H:#$i_termio I_TERMIO /**/ -?H:#$i_termios I_TERMIOS /**/ -?H:#$i_sgtty I_SGTTY /**/ -?H:. -?T:val2 val3 -?LINT:set i_termio i_sgtty i_termios -: see if this is a termio system -val="$undef" -val2="$undef" -val3="$undef" -?X: Prefer POSIX-approved termios.h over all else -if $test "`./findhdr termios.h`"; then - set tcsetattr i_termios - eval $inlibc - val3="$i_termios" -fi -echo " " -case "$val3" in -"$define") echo "You have POSIX termios.h... good!" >&4;; -*) if ./Cppsym pyr; then - case "`/bin/universe`" in - ucb) if $test "`./findhdr sgtty.h`"; then - val2="$define" - echo " found." >&4 - else - echo "System is pyramid with BSD universe." - echo " not found--you could have problems." >&4 - fi;; - *) if $test "`./findhdr termio.h`"; then - val="$define" - echo " found." >&4 - else - echo "System is pyramid with USG universe." - echo " not found--you could have problems." >&4 - fi;; - esac -?X: Start with USG to avoid problems if both usg/bsd was guessed - elif ./usg; then - if $test "`./findhdr termio.h`"; then - echo " found." >&4 - val="$define" - elif $test "`./findhdr sgtty.h`"; then - echo " found." >&4 - val2="$define" - else -echo "Neither nor found--you could have problems." >&4 - fi - else - if $test "`./findhdr sgtty.h`"; then - echo " found." >&4 - val2="$define" - elif $test "`./findhdr termio.h`"; then - echo " found." >&4 - val="$define" - else -echo "Neither nor found--you could have problems." >&4 - fi - fi;; -esac -set i_termio; eval $setvar -val=$val2; set i_sgtty; eval $setvar -val=$val3; set i_termios; eval $setvar - diff --git a/U/i_varhdr.U b/U/i_varhdr.U deleted file mode 100644 index f03da79..0000000 --- a/U/i_varhdr.U +++ /dev/null @@ -1,165 +0,0 @@ -?RCS: $Id: i_varhdr.U 1.2 Tue, 30 Sep 2003 18:01:23 -0500 dunemush $ -?RCS: -?RCS: Copyright (c) 1991-1993, Raphael Manfredi -?RCS: -?RCS: You may redistribute only under the terms of the Artistic Licence, -?RCS: as specified in the README file that comes with the distribution. -?RCS: You may reuse parts of this distribution only within the terms of -?RCS: that same Artistic Licence; a copy of which may be found at the root -?RCS: of the source tree for dist 3.0. -?RCS: -?RCS: $Log: i_varhdr.U,v $ -?RCS: Revision 3.0.1.3 1997/02/28 15:54:42 ram -?RCS: patch61: varargs script now starts with leading "startsh" -?RCS: -?RCS: Revision 3.0.1.2 1994/10/29 16:21:02 ram -?RCS: patch36: added ?F: line for metalint file checking -?RCS: -?RCS: Revision 3.0.1.1 1994/05/13 15:26:05 ram -?RCS: patch27: this unit now supersedes old i_stdarg.U and i_varargs.U -?RCS: patch27: modified to avoid spurious Whoa warnings (ADO) -?RCS: -?RCS: Revision 3.0 1993/08/18 12:08:49 ram -?RCS: Baseline for dist 3.0 netwide release. -?RCS: -?MAKE:i_stdarg i_varargs i_varhdr: cat cc ccflags rm test Setvar \ - Findhdr startsh _o ldflags -?MAKE: -pick add $@ %< -?S:i_stdarg: -?S: This variable conditionally defines the I_STDARG symbol, which -?S: indicates to the C program that exists and should -?S: be included. -?S:. -?S:i_varargs: -?S: This variable conditionally defines I_VARARGS, which indicates -?S: to the C program that it should include . -?S:. -?S:i_varhdr: -?S: Contains the name of the header to be included to get va_dcl definition. -?S: Typically one of varargs.h or stdarg.h. -?S:. -?C:I_STDARG: -?C: This symbol, if defined, indicates that exists and should -?C: be included. -?C:. -?C:I_VARARGS: -?C: This symbol, if defined, indicates to the C program that it should -?C: include . -?C:. -?H:#$i_stdarg I_STDARG /**/ -?H:. -?H:#$i_varargs I_VARARGS /**/ -?H:. -?W:%<:va_dcl -?F:!varargs -?T:valstd -?LINT:set i_stdarg i_varargs -?X: -?X: Don't use setvar because the varags test below might override these. -?X: Actually, the messages here are just informative. We don't wish to set -?X: i_varargs or i_stdarg to their final value before knowing which of the -?X: two we'll include. -?X: -: see if stdarg is available -echo " " -if $test "`./findhdr stdarg.h`"; then - echo " found." >&4 - valstd="$define" -else - echo " NOT found." >&4 - valstd="$undef" -fi - -: see if varags is available -echo " " -if $test "`./findhdr varargs.h`"; then - echo " found." >&4 -else - echo " NOT found, but that's ok (I hope)." >&4 -fi - -?X: -?X: if you have stdarg.h, you need to support prototypes to actually use it; -?X: but if stdarg.h exists and the compiler doesn't support prototypes (for some -?X: bizarre reason), we'll fall back to varargs.h anyway so it's not so bad. -?X: -: set up the varargs testing programs -$cat > varargs.c < -#endif -#ifdef I_VARARGS -#include -#endif - -#ifdef I_STDARG -int f(char *p, ...) -#else -int f(va_alist) -va_dcl -#endif -{ - va_list ap; -#ifndef I_STDARG - char *p; -#endif -#ifdef I_STDARG - va_start(ap,p); -#else - va_start(ap); - p = va_arg(ap, char *); -#endif - va_end(ap); -} -EOP -$cat > varargs </dev/null 2>&1; then - echo "true" -else - echo "false" -fi -$rm -f varargs$_o -EOP -chmod +x varargs - -: now check which varargs header should be included -echo " " -i_varhdr='' -case "$valstd" in -"$define") - if `./varargs I_STDARG`; then - val='stdarg.h' - elif `./varargs I_VARARGS`; then - val='varargs.h' - fi - ;; -*) - if `./varargs I_VARARGS`; then - val='varargs.h' - fi - ;; -esac -case "$val" in -'') -echo "I could not find the definition for va_dcl... You have problems..." >&4 - val="$undef"; set i_stdarg; eval $setvar - val="$undef"; set i_varargs; eval $setvar - ;; -*) - set i_varhdr - eval $setvar - case "$i_varhdr" in - stdarg.h) - val="$define"; set i_stdarg; eval $setvar - val="$undef"; set i_varargs; eval $setvar - ;; - varargs.h) - val="$undef"; set i_stdarg; eval $setvar - val="$define"; set i_varargs; eval $setvar - ;; - esac - echo "We'll include <$i_varhdr> to get va_dcl definition." >&4;; -esac -$rm -f varargs* - diff --git a/U/libc.U b/U/libc.U deleted file mode 100644 index e224b16..0000000 --- a/U/libc.U +++ /dev/null @@ -1,368 +0,0 @@ -?RCS: $Id: libc.U 1.1 Thu, 20 Jul 2000 17:42:54 -0500 dunemush $ -?RCS: -?RCS: Copyright (c) 1991-1993, Raphael Manfredi -?RCS: -?RCS: You may redistribute only under the terms of the Artistic Licence, -?RCS: as specified in the README file that comes with the distribution. -?RCS: You may reuse parts of this distribution only within the terms of -?RCS: that same Artistic Licence; a copy of which may be found at the root -?RCS: of the source tree for dist 3.0. -?RCS: -?RCS: $Log: libc.U,v $ -?RCS: Revision 3.0.1.10 1997/02/28 15:56:48 ram -?RCS: patch61: replaced .a with $_a all over the place -?RCS: patch61: added support for HPUX-10 nm output -?RCS: -?RCS: Revision 3.0.1.9 1995/07/25 14:11:56 ram -?RCS: patch56: now knows about OS/2 platforms -?RCS: -?RCS: Revision 3.0.1.8 1995/05/12 12:20:47 ram -?RCS: patch54: made sure only most recent version of shared lib is picked -?RCS: patch54: final "nm -p" check now uses xscan and xrun like everybody -?RCS: patch54: can now grok linux nm output with lead __IO (ADO) -?RCS: patch54: added support for linux ELF output, using 'W' for alias (ADO) -?RCS: -?RCS: Revision 3.0.1.7 1994/10/29 16:23:40 ram -?RCS: patch36: now looks for shared libraries before anything else (ADO) -?RCS: patch36: added new nm output format (ADO) -?RCS: -?RCS: Revision 3.0.1.6 1994/08/29 16:28:10 ram -?RCS: patch32: added I-type symbols for nm output parsing on Linux -?RCS: -?RCS: Revision 3.0.1.5 1994/06/20 07:03:24 ram -?RCS: patch30: checks are now presented by succession of if/elif -?RCS: patch30: uniformized checks for shared objects with new so symbol -?RCS: -?RCS: Revision 3.0.1.4 1994/05/06 15:06:33 ram -?RCS: patch23: added shared library knowledge (ADO and WED) -?RCS: -?RCS: Revision 3.0.1.3 1994/01/24 14:12:17 ram -?RCS: patch16: can now export nm_extract as an internal-use only variable -?RCS: -?RCS: Revision 3.0.1.2 1993/09/13 16:09:03 ram -?RCS: patch10: added special handling for Apollo systems (WAD) -?RCS: -?RCS: Revision 3.0.1.1 1993/08/27 14:40:03 ram -?RCS: patch7: added entry for /usr/shlib/libc.so (OSF/1 machines) -?RCS: -?RCS: Revision 3.0 1993/08/18 12:08:57 ram -?RCS: Baseline for dist 3.0 netwide release. -?RCS: -?MAKE:libc +nm_extract: echo n c rm test grep Getfile Myread Oldconfig Loc \ - sed libs incpath libpth runnm nm_opt nm_so_opt contains xlibpth so _a _o -?MAKE: -pick add $@ %< -?S:libc: -?S: This variable contains the location of the C library. -?S:. -?S:nm_extract: -?S: This variable holds the name of the extraction command used to process -?S: the output of nm and yield the list of defined symbols. It is used -?S: internally by Configure. -?S:. -?T:thislib try libnames xxx xscan xrun thisname com tans file -?F:!libnames -?LINT:change nm_opt -case "$runnm" in -true) -?X: indentation is wrong on purpose--RAM -: get list of predefined functions in a handy place -echo " " -case "$libc" in -'') libc=unknown - case "$libs" in - *-lc_s*) libc=`./loc libc_s$_a $libc $libpth` - esac - ;; -esac -libnames=''; -case "$libs" in -'') ;; -*) for thislib in $libs; do - case "$thislib" in - -lc|-lc_s) - : Handle C library specially below. - ;; - -l*) - thislib=`echo $thislib | $sed -e 's/^-l//'` - if try=`./loc lib$thislib.$so.'*' X $libpth`; $test -f "$try"; then - : - elif try=`./loc lib$thislib.$so X $libpth`; $test -f "$try"; then - : - elif try=`./loc lib$thislib$_a X $libpth`; $test -f "$try"; then - : - elif try=`./loc $thislib$_a X $libpth`; $test -f "$try"; then - : - elif try=`./loc lib$thislib X $libpth`; $test -f "$try"; then - : - elif try=`./loc $thislib X $libpth`; $test -f "$try"; then - : - elif try=`./loc Slib$thislib$_a X $xlibpth`; $test -f "$try"; then - : - else - try='' - fi - libnames="$libnames $try" - ;; - *) libnames="$libnames $thislib" ;; - esac - done - ;; -esac -?X: -?X: Some systems (e.g. DG/UX) use "environmental" links, which make the test -?X: -f fail. Ditto for symbolic links. So in order to reliably check the -?X: existence of a file, we use test -r. It will still fail with DG/UX links -?X: though, but at least it will detect symbolic links. At some strategic -?X: points, we make use of (test -h), using a sub-shell in case builtin test -?X: does not implement the -h check for symbolic links. This makes it -?X: possible to preset libc in a hint file for instance and have it show up -?X: as-is in the question. -?X: -xxx=normal -case "$libc" in -unknown) -?X: -?X: The sed below transforms .so.9 .so.12 into something like .so.0009 .so.0012, -?X: then sorts on it to allow keeping .so.12 instead of .so.9 as the latest -?X: up-to-date library. The initial filename (before sed munging, saved in hold -?X: space via 'h') is appended via 'G' before sorting, then the leading munged -?X: part is removed after sorting. Nice efficient work from Tye McQueen. -?X: The initial blurfl is here to prevent the trailing pipe from producing an -?X: empty string, causing Configure to output all its set variables! -?X: - set /lib/libc.$so - for xxx in $libpth; do - $test -r $1 || set $xxx/libc.$so - $test -r $1 || \ - set `echo blurfl; echo $xxx/libc.$so.[0-9]* | \ - tr ' ' '\012' | egrep -v '\.[A-Za-z]*$' | $sed -e ' - h - s/[0-9][0-9]*/0000&/g - s/0*\([0-9][0-9][0-9][0-9][0-9]\)/\1/g - G - s/\n/ /' | \ - sort | $sed -e 's/^.* //'` - eval set \$$# - done - $test -r $1 || set /usr/ccs/lib/libc.$so - $test -r $1 || set /lib/libsys_s$_a - ;; -*) -?X: ensure the test below for the (shared) C library will fail - set blurfl - ;; -esac -if $test -r "$1"; then - echo "Your (shared) C library seems to be in $1." - libc="$1" -elif $test -r /lib/libc && $test -r /lib/clib; then -?X: -?X: Apollo has its C library in /lib/clib AND /lib/libc -?X: not to mention its math library in /lib/syslib... -?X: - echo "Your C library seems to be in both /lib/clib and /lib/libc." - xxx=apollo - libc='/lib/clib /lib/libc' - if $test -r /lib/syslib; then - echo "(Your math library is in /lib/syslib.)" -?X: Put syslib in libc -- not quite right, but won't hurt - libc="$libc /lib/syslib" - fi -elif $test -r "$libc" || (test -h "$libc") >/dev/null 2>&1; then - echo "Your C library seems to be in $libc, as you said before." -?X: For mips, and... -elif $test -r $incpath/usr/lib/libc$_a; then - libc=$incpath/usr/lib/libc$_a; - echo "Your C library seems to be in $libc. That's fine." -elif $test -r /lib/libc$_a; then - libc=/lib/libc$_a; - echo "Your C library seems to be in $libc. You're normal." -else - if tans=`./loc libc$_a blurfl/dyick $libpth`; $test -r "$tans"; then - : - elif tans=`./loc libc blurfl/dyick $libpth`; $test -r "$tans"; then - libnames="$libnames "`./loc clib blurfl/dyick $libpth` - elif tans=`./loc clib blurfl/dyick $libpth`; $test -r "$tans"; then - : - elif tans=`./loc Slibc$_a blurfl/dyick $xlibpth`; $test -r "$tans"; then - : - elif tans=`./loc Mlibc$_a blurfl/dyick $xlibpth`; $test -r "$tans"; then - : - else - tans=`./loc Llibc$_a blurfl/dyick $xlibpth` - fi - if $test -r "$tans"; then - echo "Your C library seems to be in $tans, of all places." - libc=$tans - else - libc='blurfl' - fi -fi -if $test $xxx = apollo -o -r "$libc" || (test -h "$libc") >/dev/null 2>&1; then - dflt="$libc" - cat < libpath - cat >&4 < libnames -set X `cat libnames` -shift -xxx=files -case $# in 1) xxx=file; esac -echo "Extracting names from the following $xxx for later perusal:" >&4 -echo " " -$sed 's/^/ /' libnames >&4 -echo " " -$echo $n "This may take a while...$c" >&4 - -?X: -?X: Linux may need the special Dynamic option to nm for shared libraries. -?X: In general, this is stored in the nm_so_opt variable. -?X: Unfortunately, that option may be fatal on non-shared libraries. -?X: -for file in $*; do - case $file in - *$so*) nm $nm_so_opt $nm_opt $file 2>/dev/null;; - *) nm $nm_opt $file 2>/dev/null;; - esac -done >libc.tmp - -$echo $n ".$c" -?X: -?X: To accelerate processing, we look at the correct 'sed' command -?X: by using a small subset of libc.tmp, i.e. fprintf function. -?X: When we know which sed command to use, do the name extraction -?X: -$grep fprintf libc.tmp > libc.ptf -?X: -?X: In order to ehance readability and save some space, we define -?X: some variables that will be "eval"ed. -?X: -xscan='eval "libc.list"; $echo $n ".$c" >&4' -xrun='eval "libc.list"; echo "done" >&4' -?X: BSD-like output, I and W types added for Linux -?X: Some versions of Linux include a leading __IO in the symbol name. -?X: HPUX10 reportedly has trailing spaces, though I'm suprised it has -?X: BSD-like output. (AD). -xxx='[ADTSIW]' -if com="$sed -n -e 's/__IO//' -e 's/^.* $xxx *_[_.]*//p' -e 's/^.* $xxx *//p'";\ - eval $xscan;\ - $contains '^fprintf$' libc.list >/dev/null 2>&1; then - eval $xrun -?X: SYSV-like output -elif com="$sed -n -e 's/^__*//' -e 's/^\([a-zA-Z_0-9$]*\).*xtern.*/\1/p'";\ - eval $xscan;\ - $contains '^fprintf$' libc.list >/dev/null 2>&1; then - eval $xrun -elif com="$sed -n -e '/|UNDEF/d' -e '/FUNC..GL/s/^.*|__*//p'";\ - eval $xscan;\ - $contains '^fprintf$' libc.list >/dev/null 2>&1; then - eval $xrun -elif com="$sed -n -e 's/^.* D __*//p' -e 's/^.* D //p'";\ - eval $xscan;\ - $contains '^fprintf$' libc.list >/dev/null 2>&1; then - eval $xrun -elif com="$sed -n -e 's/^_//' -e 's/^\([a-zA-Z_0-9]*\).*xtern.*text.*/\1/p'";\ - eval $xscan;\ - $contains '^fprintf$' libc.list >/dev/null 2>&1; then - eval $xrun -elif com="$sed -n -e 's/^.*|FUNC |GLOB .*|//p'";\ - eval $xscan;\ - $contains '^fprintf$' libc.list >/dev/null 2>&1; then - eval $xrun -elif com="$grep '|' | $sed -n -e '/|COMMON/d' -e '/|DATA/d' \ - -e '/ file/d' -e 's/^\([^ ]*\).*/\1/p'";\ - eval $xscan;\ - $contains '^fprintf$' libc.list >/dev/null 2>&1; then - eval $xrun -elif com="$sed -n -e 's/^.*|FUNC |GLOB .*|//p' -e 's/^.*|FUNC |WEAK .*|//p'";\ - eval $xscan;\ - $contains '^fprintf$' libc.list >/dev/null 2>&1; then - eval $xrun -?X: mips nm output (sysV) -elif com="$sed -n -e 's/^__//' -e '/|Undef/d' -e '/|Proc/s/ .*//p'";\ - eval $xscan;\ - $contains '^fprintf$' libc.list >/dev/null 2>&1; then - eval $xrun -elif com="$sed -n -e '/Def. Text/s/.* \([^ ]*\)\$/\1/p'";\ - eval $xscan;\ - $contains '^fprintf$' libc.list >/dev/null 2>&1; then - eval $xrun -?X: OS/2 nm output -elif com="$sed -n -e 's/^[-0-9a-f ]*_\(.*\)=.*/\1/p'";\ - eval $xscan;\ - $contains '^fprintf$' libc.list >/dev/null 2>&1; then - eval $xrun -elif com="$sed -n -e 's/.*\.text n\ \ \ \.//p'";\ - eval $xscan;\ - $contains '^fprintf$' libc.list >/dev/null 2>&1; then - eval $xrun -else - nm -p $* 2>/dev/null >libc.tmp - $grep fprintf libc.tmp > libc.ptf - if com="$sed -n -e 's/^.* [ADTSIW] *_[_.]*//p' -e 's/^.* [ADTSIW] //p'";\ - eval $xscan; $contains '^fprintf$' libc.list >/dev/null 2>&1 - then - nm_opt='-p' - eval $xrun - else - echo " " - echo "nm didn't seem to work right. Trying ar instead..." >&4 - com='' - if ar t $libc > libc.tmp; then - for thisname in $libnames; do - ar t $thisname >>libc.tmp - done - $sed -e "s/\\$_o\$//" < libc.tmp > libc.list - echo "Ok." >&4 - else - echo "ar didn't seem to work right." >&4 - echo "Maybe this is a Cray...trying bld instead..." >&4 - if bld t $libc | $sed -e 's/.*\///' -e "s/\\$_o:.*\$//" > libc.list - then - for thisname in $libnames; do - bld t $libnames | \ - $sed -e 's/.*\///' -e "s/\\$_o:.*\$//" >>libc.list - ar t $thisname >>libc.tmp - done - echo "Ok." >&4 - else - echo "That didn't work either. Giving up." >&4 - exit 1 - fi - fi - fi -fi -nm_extract="$com" -if $test -f /lib/syscalls.exp; then - echo " " - echo "Also extracting names from /lib/syscalls.exp for good ole AIX..." >&4 - $sed -n 's/^\([^ ]*\)[ ]*syscall$/\1/p' /lib/syscalls.exp >>libc.list -fi -?X: remember, indentation is wrong on purpose--RAM -;; -esac -$rm -f libnames libpath - diff --git a/U/libmysqlclient.U b/U/libmysqlclient.U deleted file mode 100644 index 52c1ea7..0000000 --- a/U/libmysqlclient.U +++ /dev/null @@ -1,64 +0,0 @@ -?RCS: $Id$ -?RCS: -?RCS: -?MAKE:libmysqlclient d_mysql: test Loc libpth _a cc ccflags ldflags libs rm cat -?MAKE: -pick add $@ %< -?S:libmysqlclient: -?S: This variable contains the argument to pass to the loader in order -?S: to get the ssl library routines. If there is no mysql -?S: library, it is null. -?S:. -?S:d_mysql: -?S: Defined if mysql client libraries are available. -?S:. -?C:HAS_MYSQL: -?C: Defined if mysql client libraries are available. -?C:. -?H:#$d_mysql HAS_MYSQL /**/ -?H:. -?T:xxx -: see if we should include -lmysqlclient -echo " " - -d_mysql="$undef" - -if $test "x$no_mysql" = "x"; then - - libmysqlclient="-lmysqlclient" - - $cat > test_mysql.c < -#include -#include -#include - -int main(int argc, char **argv) { - printf("Your mysql is version %s\n",mysql_get_client_info()); - exit(0); -} -EOM - - if $cc $ccflags $ldflags -o test_mysql test_mysql.c $libs $libmysqlclient >/dev/null 2>&1 ; - then - echo 'You have mysql...' >&4 - version=`./test_mysql` - if $test $? -eq 0; then - echo "$version" >&4 - d_mysql="$define" - else - echo "...but my test program didn't run correctly." >&4 - libmysqlclient='' - fi - else - echo "You don't seem to have mysql." >&4 - libmysqlclient='' - fi - $rm -f test_mysql* core - -else - - echo "Skipping mysql tests." >&4 - libmysqlclient='' - -fi - diff --git a/U/libpth.U b/U/libpth.U deleted file mode 100644 index b468243..0000000 --- a/U/libpth.U +++ /dev/null @@ -1,132 +0,0 @@ -?RCS: $Id: libpth.U 1 2006-08-24 12:32:52Z rmanfredi $ -?RCS: -?RCS: Copyright (c) 1991-1997, 2004-2006, Raphael Manfredi -?RCS: -?RCS: You may redistribute only under the terms of the Artistic Licence, -?RCS: as specified in the README file that comes with the distribution. -?RCS: You may reuse parts of this distribution only within the terms of -?RCS: that same Artistic Licence; a copy of which may be found at the root -?RCS: of the source tree for dist 4.0. -?RCS: -?RCS: $Log: libpth.U,v $ -?RCS: Revision 3.0.1.6 1997/02/28 16:08:49 ram -?RCS: patch61: new loclibpth variable -?RCS: -?RCS: Revision 3.0.1.5 1995/01/11 15:31:30 ram -?RCS: patch45: call ./mips instead of just mips (WED) -?RCS: -?RCS: Revision 3.0.1.4 1994/08/29 16:29:15 ram -?RCS: patch32: added /lib/pa1.1 for HP-UX specially tuned PA-RISC libs (ADO) -?RCS: patch32: fixed information message, making it clearer (ADO) -?RCS: -?RCS: Revision 3.0.1.3 1994/06/20 07:03:54 ram -?RCS: patch30: added /usr/shlib to glibpth for shared-only libraries -?RCS: -?RCS: Revision 3.0.1.2 1994/05/13 15:26:57 ram -?RCS: patch27: fixed a typo (libpth -> glibpth) -?RCS: -?RCS: Revision 3.0.1.1 1994/05/06 15:07:53 ram -?RCS: patch23: now asks for library directories to be searched (ADO) -?RCS: -?RCS: Revision 3.0 1993/08/18 12:09:02 ram -?RCS: Baseline for dist 3.0 netwide release. -?RCS: -?X: -?X: This unit initializes the path for C library lookup. -?X: -?MAKE:libpth glibpth xlibpth plibpth loclibpth: \ - usrinc incpath test cat Myread Oldconfig -?MAKE: -pick add $@ %< -?S:libpth: -?S: This variable holds the general path (space-separated) used to find -?S: libraries. It is intended to be used by other units. -?S:. -?S:glibpth: -?S: This variable holds the general path (space-separated) used to -?S: find libraries. It may contain directories that do not exist on -?S: this platform, libpth is the cleaned-up version. -?S:. -?S:xlibpth: -?S: This variable holds extra path (space-separated) used to find -?S: libraries on this platform, for example CPU-specific libraries -?S: (on multi-CPU platforms) may be listed here. -?S:. -?S:loclibpth: -?S: This variable holds the paths (space-separated) used to find local -?S: libraries. It is prepended to libpth, and is intended to be easily -?S: set from the command line. -?S:. -?S:plibpth: -?S: Holds the private path used by Configure to find out the libraries. -?S: Its value is prepend to libpth. This variable takes care of special -?S: machines, like the mips. Usually, it should be empty. -?S:. -?T: xxx dlist -?LINT:use usrinc -?INIT:: change the next line if compiling for Xenix/286 on Xenix/386 -?INIT:xlibpth='/usr/lib/386 /lib/386' -?INIT:: Possible local library directories to search. -?INIT:loclibpth="/usr/local/lib /opt/local/lib /usr/gnu/lib" -?INIT:loclibpth="$loclibpth /opt/gnu/lib /usr/GNU/lib /opt/GNU/lib" -?INIT: -?INIT:: general looking path for locating libraries -?INIT:glibpth="/lib /usr/lib $xlibpth" -?INIT:glibpth="$glibpth /usr/ccs/lib /usr/ucblib /usr/local/lib" -?X: /shlib is for Digital Unix 4.0 -?X: /usr/shlib is for OSF/1 systems. -?INIT:test -f /usr/shlib/libc.so && glibpth="/usr/shlib $glibpth" -?INIT:test -f /shlib/libc.so && glibpth="/shlib $glibpth" -?INIT: -?INIT:: Private path used by Configure to find libraries. Its value -?INIT:: is prepended to libpth. This variable takes care of special -?INIT:: machines, like the mips. Usually, it should be empty. -?INIT:plibpth='' -?INIT: -: Set private lib path -case "$plibpth" in -'') if ./mips; then -?X: on mips, we DO NOT want /lib, and we want $incpath/usr/lib - plibpth="$incpath/usr/lib /usr/local/lib /usr/ccs/lib" - fi;; -esac -case "$libpth" in -' ') dlist='';; -'') dlist="$loclibpth $plibpth $glibpth";; -*) dlist="$libpth";; -esac - -: Now check and see which directories actually exist, avoiding duplicates -libpth='' -for xxx in $dlist -do - if $test -d $xxx; then - case " $libpth " in - *" $xxx "*) ;; - *) libpth="$libpth $xxx";; - esac - fi -done -$cat <<'EOM' - -Some systems have incompatible or broken versions of libraries. Among -the directories listed in the question below, please remove any you -know not to be holding relevant libraries, and add any that are needed. -Say "none" for none. - -EOM -case "$libpth" in -'') dflt='none';; -*) -?X: strip leading space - set X $libpth - shift - dflt=${1+"$@"} - ;; -esac -rp="Directories to use for library searches?" -. ./myread -case "$ans" in -none) libpth=' ';; -*) libpth="$ans";; -esac - diff --git a/U/libs.U b/U/libs.U deleted file mode 100644 index d6feb23..0000000 --- a/U/libs.U +++ /dev/null @@ -1,213 +0,0 @@ -?RCS: $Id: libs.U 1.1 Thu, 20 Jul 2000 17:42:54 -0500 dunemush $ -?RCS: -?RCS: Copyright (c) 1991-1993, Raphael Manfredi -?RCS: -?RCS: You may redistribute only under the terms of the Artistic Licence, -?RCS: as specified in the README file that comes with the distribution. -?RCS: You may reuse parts of this distribution only within the terms of -?RCS: that same Artistic Licence; a copy of which may be found at the root -?RCS: of the source tree for dist 3.0. -?RCS: -?RCS: $Log: libs.U,v $ -?RCS: Revision 3.0.1.6 1997/02/28 16:09:11 ram -?RCS: patch61: replaced .a with $_a all over the place -?RCS: -?RCS: Revision 3.0.1.5 1995/07/25 14:12:05 ram -?RCS: patch56: now knows about OS/2 platforms -?RCS: -?RCS: Revision 3.0.1.4 1994/10/29 16:24:22 ram -?RCS: patch36: removed old broken thislib/thatlib processing (ADO) -?RCS: -?RCS: Revision 3.0.1.3 1994/06/20 07:05:44 ram -?RCS: patch30: code cleanup with if/elif by ADO and RAM -?RCS: patch30: undone patch23 for libswanted default setting -?RCS: -?RCS: Revision 3.0.1.2 1994/05/06 15:08:45 ram -?RCS: patch23: now includes ordered default libswanted variable (ADO) -?RCS: patch23: major cleanup for library lookups (ADO) -?RCS: -?RCS: Revision 3.0.1.1 1993/08/25 14:02:31 ram -?RCS: patch6: added default for libs -?RCS: -?RCS: Revision 3.0 1993/08/18 12:09:03 ram -?RCS: Baseline for dist 3.0 netwide release. -?RCS: -?MAKE:libs: test cat Myread Oldconfig Loc libpth package xlibpth so _a -?MAKE: -pick add $@ %< -?S:libs: -?S: This variable holds the additional libraries we want to use. -?S: It is up to the Makefile to deal with it. -?S:. -?T:xxx thislib libswanted -?D:libs='' -?X: -?X: This order is chosen so that libraries -lndir, -ldir, -lucb, -lbsd, -?X: -lBSD, -lPW, and -lx only get used if there are unresolved -?X: routines at link time. Usually, these are backwards compatability -?X: libraries, and may not be as reliable as the standard c library. -?X: -?X: The -lsocket -linet -lnsl order has been reported to be necessary -?X: for at least one SVR4 implementation. -?X: -lc must proceed -lucb or -lbsd for most Solaris applications. -?X: -lc_s proceeds -lc so we pick up the shared library version, if -?X: it is available. -?X: -?X: The ordering of c, posix, and cposix is a guess and almost -?X: certainly wrong on about half of all systems. -?X: -?X: Set proper libswanted in your private Myinit.U if needed. -?X: -?X:: default ordered library list -?X:libswanted='net socket inet nsl nm sdbm gdbm ndbm dbm malloc dl' -?X:libswanted="$libswanted dld sun m c_s c posix cposix ndir dir ucb" -?X:libswanted="$libswanted bsd BSD PW x" -?X: -?INIT:: default library list -?INIT:libswanted='' -: Looking for optional libraries -echo " " -echo "Checking for optional libraries..." >&4 -case "$libs" in -' '|'') dflt='';; -*) dflt="$libs";; -esac -case "$libswanted" in -'') libswanted='c_s';; -esac -for thislib in $libswanted; do - -?X: -?X: Comparaisons via case statement use the string " $dflt " to ensure that -?X: each library is separated by a space. That way, by looking to something -?X: like *"-l$thislib "*, we ensure we find -lm and not -lmalloc (which was -?X: the case with the old looking pattern *-l$thislib*. -?X: - -?X: A kludge - if we find libbind, we don't want libresolv - - if $test "$thislib" = "resolv"; then - case " $dflt " in - *"-lbind "*) echo "We've already found -lbind, so we don't need -lresolv" ;; - *"-lbind9 "*) echo "We've already found -lbind9, so we don't need -lresolv";; - *) - - if xxx=`./loc lib$thislib.$so.[0-9]'*' X $libpth`; $test -f "$xxx"; then - echo "Found -l$thislib (shared)." - case " $dflt " in - *"-l$thislib "*);; - *) dflt="$dflt -l$thislib";; - esac - elif xxx=`./loc lib$thislib.$so X $libpth` ; $test -f "$xxx"; then - echo "Found -l$thislib (shared)." - case " $dflt " in - *"-l$thislib "*);; - *) dflt="$dflt -l$thislib";; - esac - elif xxx=`./loc lib$thislib$_a X $libpth`; $test -f "$xxx"; then - echo "Found -l$thislib." - case " $dflt " in - *"-l$thislib "*);; - *) dflt="$dflt -l$thislib";; - esac -?X: Don't forget about OS/2 where -lmalloc is spelled out malloc.a - elif xxx=`./loc $thislib$_a X $libpth`; $test -f "$xxx"; then - echo "Found -l$thislib." - case " $dflt " in - *"-l$thislib "*);; - *) dflt="$dflt -l$thislib";; - esac - elif xxx=`./loc lib${thislib}_s$_a X $libpth`; $test -f "$xxx"; then - echo "Found -l${thislib}_s." - case " $dflt " in - *"-l$thislib "*);; - *) dflt="$dflt -l${thislib}_s";; - esac - elif xxx=`./loc Slib$thislib$_a X $xlibpth`; $test -f "$xxx"; then - echo "Found -l$thislib." - case " $dflt " in - *"-l$thislib "*);; - *) dflt="$dflt -l$thislib";; - esac - else - echo "No -l$thislib." - fi - - ;; - esac - else - - if xxx=`./loc lib$thislib.$so.[0-9]'*' X $libpth`; $test -f "$xxx"; then - echo "Found -l$thislib (shared)." - case " $dflt " in - *"-l$thislib "*);; - *) dflt="$dflt -l$thislib";; - esac - elif xxx=`./loc lib$thislib.$so X $libpth` ; $test -f "$xxx"; then - echo "Found -l$thislib (shared)." - case " $dflt " in - *"-l$thislib "*);; - *) dflt="$dflt -l$thislib";; - esac - elif xxx=`./loc lib$thislib$_a X $libpth`; $test -f "$xxx"; then - echo "Found -l$thislib." - case " $dflt " in - *"-l$thislib "*);; - *) dflt="$dflt -l$thislib";; - esac -?X: Don't forget about OS/2 where -lmalloc is spelled out malloc.a - elif xxx=`./loc $thislib$_a X $libpth`; $test -f "$xxx"; then - echo "Found -l$thislib." - case " $dflt " in - *"-l$thislib "*);; - *) dflt="$dflt -l$thislib";; - esac - elif xxx=`./loc lib${thislib}_s$_a X $libpth`; $test -f "$xxx"; then - echo "Found -l${thislib}_s." - case " $dflt " in - *"-l$thislib "*);; - *) dflt="$dflt -l${thislib}_s";; - esac - elif xxx=`./loc Slib$thislib$_a X $xlibpth`; $test -f "$xxx"; then - echo "Found -l$thislib." - case " $dflt " in - *"-l$thislib "*);; - *) dflt="$dflt -l$thislib";; - esac - else - echo "No -l$thislib." - fi - - fi -done -set X $dflt -shift -dflt="$*" -case "$libs" in -'') dflt="$dflt";; -*) dflt="$libs";; -esac -case "$dflt" in -' '|'') dflt='none';; -esac - -$cat < test_ssl.c < -#include -#include -int main(int argc, char **argv) { - printf("Your openssl is version %lx\n",OPENSSL_VERSION_NUMBER); - exit(OPENSSL_VERSION_NUMBER < 0x00906000L); -} -EOM - - if $cc $ccflags $ldflags -o test_ssl test_ssl.c $libs $libssl >/dev/null 2>&1 ; - then - echo 'You have openssl...' >&4 - version=`./test_ssl` - if $test $? -eq 0; then - echo '...and at least version 0.9.6. Great.' >&4 - d_openssl="$define" - else - echo '...but not version 0.9.6 or later.' >&4 - libssl='' - fi - else - echo "You don't seem to have openssl." >&4 - libssl='' - fi - $rm -f test_ssl* core - -else - - echo "Skipping openssl tests." >&4 - libssl='' - -fi - diff --git a/U/mailer.U b/U/mailer.U deleted file mode 100644 index f55285b..0000000 --- a/U/mailer.U +++ /dev/null @@ -1,65 +0,0 @@ -?RCS: $Id: mailer.U 1.1 Thu, 20 Jul 2000 17:42:54 -0500 dunemush $ -?RCS: -?RCS: Copyright (c) 1991-1993, Raphael Manfredi -?RCS: -?RCS: You may redistribute only under the terms of the Artistic Licence, -?RCS: as specified in the README file that comes with the distribution. -?RCS: You may reuse parts of this distribution only within the terms of -?RCS: that same Artistic Licence; a copy of which may be found at the root -?RCS: of the source tree for dist 3.0. -?RCS: -?RCS: $Log: mailer.U,v $ -?RCS: Revision 3.0.1.3 1995/01/11 15:32:11 ram -?RCS: patch45: can now use Loc variables since path stripping is deferred -?RCS: -?RCS: Revision 3.0.1.2 1994/05/06 15:10:04 ram -?RCS: patch23: ensure full path value is used for rmail also -?RCS: -?RCS: Revision 3.0.1.1 1994/01/24 14:14:18 ram -?RCS: patch16: now use _sendmail vars and friends for portability issues -?RCS: -?RCS: Revision 3.0 1993/08/18 12:09:10 ram -?RCS: Baseline for dist 3.0 netwide release. -?RCS: -?MAKE:mailer: test cat rmail mail smail sendmail Getfile Oldconfig package -?MAKE: -pick add $@ %< -?S:mailer: -?S: This variable contains the full pathname of a reasonable mailer. -?S: By reasonable, we mean some program which can understand internet -?S: addresses or at least forward them to some internet router. This -?S: mailer should be invoked as "mailer [options] recipients /etc/passwd (WED) -?RCS: -?RCS: Revision 3.0.1.1 1993/09/13 16:10:09 ram -?RCS: patch10: made questions more explicit for 'Configure -s' prompting (WAD) -?RCS: -?RCS: Revision 3.0 1993/08/18 12:09:20 ram -?RCS: Baseline for dist 3.0 netwide release. -?RCS: -?MAKE:nametype d_passnames d_berknames d_usgnames: Myread Guess Oldconfig cat test osname -?MAKE: -pick add $@ %< -?S:nametype: -?S: This variable indicates how full names are stored on this system. -?S: Values are bsd, usg, and other. -?S:. -?S:d_passnames: -?S: This variable conditionally defines the PASSNAMES symbol, -?S: which indicates to the C program that full names are stored in -?S: the /etc/passwd file. -?S:. -?S:d_berknames: -?S: This variable conditionally defines the PASSNAMES symbol, -?S: which indicates to the C program that full names are stored in -?S: the /etc/passwd file in Berkeley format. -?S:. -?S:d_usgnames: -?S: This variable conditionally defines the PASSNAMES symbol, -?S: which indicates to the C program that full names are stored in -?S: the /etc/passwd file in USG format. -?S:. -?C:PASSNAMES: -?C: This symbol, if defined, indicates that full names are stored in -?C: the /etc/passwd file. -?C:. -?C:BERKNAMES: -?C: This symbol, if defined, indicates that full names are stored in -?C: the /etc/passwd file in Berkeley format (name first thing, everything -?C: up to first comma, with & replaced by capitalized login id, yuck). -?C:. -?C:USGNAMES: -?C: This symbol, if defined, indicates that full names are stored in -?C: the /etc/passwd file in USG format (everything after - and before ( is -?C: the name). -?C:. -?H:#$d_passnames PASSNAMES /* (undef to take name from ~/.fullname) */ -?H:#$d_berknames BERKNAMES /* (that is, ":name,stuff:") */ -?H:#$d_usgnames USGNAMES /* (that is, ":stuff-name(stuff):") */ -?H:. -: find out how to find out full name -case "$d_berknames" in -"$define") - dflt=y;; -"$undef") - dflt=n;; -*) - if ./bsd; then - dflt=y - elif ./xenix; then - dflt=y - elif $test "x$osname" = "xlinux"; then - dflt=y - else - dflt=n - fi - ;; -esac -$cat <<'EOM' - -Does your /etc/passwd file keep full names in Berkeley/V7 format (name first -thing after ':' in GCOS field)? In that case, a typical entry in the password -file looks like this: - - guest:**paswword**:10:100:Mister Guest User:/usr/users:/bin/sh - ^^^^^^^^^^^^^^^^^ -EOM -rp="Berkeley/V7 format for full name in /etc/passwd?" -. ./myread -case "$ans" in -y*) d_passnames="$define" - d_berknames="$define" - d_usgnames="$undef" - nametype=bsd - ;; -*) - case "$d_usgnames" in - "$define") dflt=y;; - "$undef") dflt=n;; - *) - if ./usg; then - dflt=y - else - dflt=n - fi - ;; - esac -$cat <<'EOM' - -Does your passwd file keep full names in USG format (name sandwiched between a -'-' and a '(')? In that case, a typical entry in the password file looks like -this: - - guest:**paswword**:10:100:000-Mister Guest User(000):/usr/users:/bin/sh - ^^^^^^^^^^^^^^^^^ -EOM - rp="USG format for full name in /etc/passwd?" - . ./myread - case "$ans" in - n*) echo "Full name will be taken from ~/.fullname" - d_passnames="$undef" - d_berknames="$undef" - d_usgnames="$undef" - nametype=other - ;; - *) - d_passnames="$define" - d_berknames="$undef" - d_usgnames="$define" - nametype=usg - ;; - esac;; -esac - diff --git a/U/sockopt.U b/U/sockopt.U deleted file mode 100644 index 683987c..0000000 --- a/U/sockopt.U +++ /dev/null @@ -1,120 +0,0 @@ -?RCS: $Id$ -?RCS: -?RCS: Copyright (c) 1991-1993, Raphael Manfredi -?RCS: -?RCS: You may redistribute only under the terms of the Artistic Licence, -?RCS: as specified in the README file that comes with the distribution. -?RCS: You may reuse parts of this distribution only within the terms of -?RCS: that same Artistic Licence; a copy of which may be found at the root -?RCS: of the source tree for dist 3.0. -?RCS: -?RCS: $Log: sockopt.U,v $ -?RCS: Revision 3.0.1.1 1995/07/25 14:16:14 ram -?RCS: patch56: obsoleted KEEPALIVE in favor of CAN_KEEPALIVE for consistency -?RCS: -?RCS: Revision 3.0 1993/08/18 12:09:48 ram -?RCS: Baseline for dist 3.0 netwide release. -?RCS: -?MAKE:d_keepalive d_keepidle: cat rm contains +cc +ccflags socketlib sockethdr \ - d_oldsock libs Oldconfig Setvar Findhdr i_nitcp -?MAKE: -pick add $@ %< -?S:d_keepalive: -?S: This symbol conditionally defines CAN_KEEPALIVE which indicates to the C -?S: program that setsockopt SO_KEEPALIVE will work properly. -?S:. -?S:d_keepidle: -?S: This symbol conditionally defines CAN_KEEPIDLE which indicates to the C -?S: program that setsockopt TCP_KEEPIDLE will work properly. -?S:. -?C:CAN_KEEPALIVE: -?C: This symbol if defined indicates to the C program that the SO_KEEPALIVE -?C: option of setsockopt() will work as advertised in the manual. -?C:. -?C:CAN_KEEPIDLE: -?C: This symbol if defined indicates to the C program that the TCP_KEEPIDLE -?C: option of setsockopt() will work as advertised in the manual. -?C:. -?H:#$d_keepalive CAN_KEEPALIVE /**/ -?H:. -?H:#$d_keepidle CAN_KEEPIDLE /**/ -?H:. -?LINT:set d_keepalive d_keepidle -: see if setsockopt with SO_KEEPALIVE works as advertised -echo " " -case "$d_oldsock" in -"$undef") - echo "OK, let's see if SO_KEEPALIVE works as advertised..." >&4 - $cat > socket.c < -#include -#include -#$i_nitcp I_NETINET_TCP -#ifdef I_NETINET_TCP -#include -#endif -#include - -main() -{ - int s = socket(AF_INET, SOCK_STREAM, 0); - int val = 1; - if (s == -1) - exit(1); - if (-1 == setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val))) - exit(2); -#ifdef I_NETINET_TCP -#ifdef TCP_KEEPIDLE - val = 1; - if (-1 == setsockopt(s, IPPROTO_TCP, TCP_KEEPIDLE, &val, sizeof(val))) - exit(3); -#else - exit(3); -#endif -#endif - exit(0); -} -EOP - if $cc $ccflags $sockethdr socket.c -o socket $libs \ - $socketlib >/dev/null 2>&1; then - ./socket >/dev/null 2>&1 - case $? in - 0) echo "Yes, it does!" - val="$define" - val2="$i_nitcp" - ;; - 1) $cat </dev/null` - if $test $dflt -gt 20; then - dflt=y - else - dflt=n - fi - ;; - esac - ;; -*) - case "$usenm" in - true) dflt=y;; - *) dflt=n;; - esac - ;; -esac -$cat < /dev/null 2>&1; then - nm_so_opt='--dynamic' - fi - ;; - esac - ;; -esac - diff --git a/aclocal.m4 b/aclocal.m4 new file mode 100644 index 0000000..18a6cb5 --- /dev/null +++ b/aclocal.m4 @@ -0,0 +1,1320 @@ +# DO NOT RUN ACLOCAL TO GENERATE THIS FILE! +# Some of the macros have been changed from the stock versions. +# Namely, CHECK_SSL. + + +# =========================================================================== +# http://autoconf-archive.cryp.to/ax_lib_mysql.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_LIB_MYSQL([MINIMUM-VERSION]) +# +# DESCRIPTION +# +# This macro provides tests of availability of MySQL client library of +# particular version or newer. +# +# AX_LIB_MYSQL macro takes only one argument which is optional. If there +# is no required version passed, then macro does not run version test. +# +# The --with-mysql option takes one of three possible values: +# +# no - do not check for MySQL client library +# +# yes - do check for MySQL library in standard locations (mysql_config +# should be in the PATH) +# +# path - complete path to mysql_config utility, use this option if +# mysql_config can't be found in the PATH +# +# This macro calls: +# +# AC_SUBST(MYSQL_CFLAGS) +# AC_SUBST(MYSQL_LDFLAGS) +# AC_SUBST(MYSQL_VERSION) +# +# And sets: +# +# HAVE_MYSQL +# +# LAST MODIFICATION +# +# 2008-04-12 +# +# COPYLEFT +# +# Copyright (c) 2008 Mateusz Loskot +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. + +AC_DEFUN([AX_LIB_MYSQL], +[ + AC_ARG_WITH([mysql], + AC_HELP_STRING([--with-mysql=@<:@ARG@:>@], + [use MySQL client library @<:@default=yes@:>@, optionally specify path to mysql_config] + ), + [ + if test "$withval" = "no"; then + want_mysql="no" + elif test "$withval" = "yes"; then + want_mysql="yes" + else + want_mysql="yes" + MYSQL_CONFIG="$withval" + fi + ], + [want_mysql="yes"] + ) + + MYSQL_CFLAGS="" + MYSQL_LDFLAGS="" + MYSQL_VERSION="" + + dnl + dnl Check MySQL libraries (libpq) + dnl + + if test "$want_mysql" = "yes"; then + + if test -z "$MYSQL_CONFIG" -o test; then + AC_PATH_PROG([MYSQL_CONFIG], [mysql_config], [no]) + fi + + if test "$MYSQL_CONFIG" != "no"; then + AC_MSG_CHECKING([for MySQL libraries]) + + MYSQL_CFLAGS="`$MYSQL_CONFIG --cflags`" + MYSQL_LDFLAGS="`$MYSQL_CONFIG --libs`" + + MYSQL_VERSION=`$MYSQL_CONFIG --version` + + AC_DEFINE([HAVE_MYSQL], [1], + [Define to 1 if MySQL libraries are available]) + + found_mysql="yes" + AC_MSG_RESULT([yes]) + else + found_mysql="no" +dnl AC_MSG_RESULT([no]) + fi + fi + + dnl + dnl Check if required version of MySQL is available + dnl + + + mysql_version_req=ifelse([$1], [], [], [$1]) + + if test "$found_mysql" = "yes" -a -n "$mysql_version_req"; then + + AC_MSG_CHECKING([if MySQL version is >= $mysql_version_req]) + + dnl Decompose required version string of MySQL + dnl and calculate its number representation + mysql_version_req_major=`expr $mysql_version_req : '\([[0-9]]*\)'` + mysql_version_req_minor=`expr $mysql_version_req : '[[0-9]]*\.\([[0-9]]*\)'` + mysql_version_req_micro=`expr $mysql_version_req : '[[0-9]]*\.[[0-9]]*\.\([[0-9]]*\)'` + if test "x$mysql_version_req_micro" = "x"; then + mysql_version_req_micro="0" + fi + + mysql_version_req_number=`expr $mysql_version_req_major \* 1000000 \ + \+ $mysql_version_req_minor \* 1000 \ + \+ $mysql_version_req_micro` + + dnl Decompose version string of installed MySQL + dnl and calculate its number representation + mysql_version_major=`expr $MYSQL_VERSION : '\([[0-9]]*\)'` + mysql_version_minor=`expr $MYSQL_VERSION : '[[0-9]]*\.\([[0-9]]*\)'` + mysql_version_micro=`expr $MYSQL_VERSION : '[[0-9]]*\.[[0-9]]*\.\([[0-9]]*\)'` + if test "x$mysql_version_micro" = "x"; then + mysql_version_micro="0" + fi + + mysql_version_number=`expr $mysql_version_major \* 1000000 \ + \+ $mysql_version_minor \* 1000 \ + \+ $mysql_version_micro` + + mysql_version_check=`expr $mysql_version_number \>\= $mysql_version_req_number` + if test "$mysql_version_check" = "1"; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + fi + fi + + AC_SUBST([MYSQL_VERSION]) + AC_SUBST([MYSQL_CFLAGS]) + AC_SUBST([MYSQL_LDFLAGS]) +]) + +# +# SYNOPSIS +# +# CHECK_SSL +# +# DESCRIPTION +# +# This macro will check various standard spots for OpenSSL including +# a user-supplied directory. The user uses '--with-ssl' or +# '--with-ssl=/path/to/ssl' as arguments to configure. +# +# If OpenSSL is found the include directory gets added to CFLAGS and +# CXXFLAGS as well as '-DHAVE_SSL', '-lssl' & '-lcrypto' get added to +# LIBS, and the libraries location gets added to LDFLAGS. Finally +# 'HAVE_SSL' gets set to 'yes' for use in your Makefile.in I use it +# like so (valid for gmake): +# +# HAVE_SSL = @HAVE_SSL@ +# ifeq ($(HAVE_SSL),yes) +# SRCS+= @srcdir@/my_file_that_needs_ssl.c +# endif +# +# For bsd 'bmake' use: +# +# .if ${HAVE_SSL} == "yes" +# SRCS+= @srcdir@/my_file_that_needs_ssl.c +# .endif +# +# LAST MODIFICATION +# +# 2003-01-28 +# +# COPYLEFT +# +# Copyright (c) 2003 Mark Ethan Trostler +# +# Copying and distribution of this file, with or without +# modification, are permitted in any medium without royalty provided +# the copyright notice and this notice are preserved. + +AC_DEFUN(CHECK_SSL, +[AC_ARG_WITH(ssl, + +[ +AC_HELP_STRING([--with-ssl=@<:@DIR@:>@], [look for OpenSSL in DIR (Use when it's not found with the default search path)]) +], + +[ AS_IF([test "x$with_ssl" != xno], + [ AC_MSG_CHECKING([for OpenSSL]) + for dir in $with_ssl /usr/local/ssl /usr/lib/ssl /usr/ssl /usr/pkg /usr/local /usr; do + ssldir="$dir" + if test -f "$dir/include/openssl/ssl.h"; then + found_ssl="yes"; + CFLAGS="$CFLAGS -I$ssldir/include/"; + break; + fi + if test -f "$dir/include/ssl.h"; then + found_ssl="yes"; + CFLAGS="$CFLAGS -I$ssldir/include/"; + break; + fi + done + if test x_$found_ssl != x_yes; then + AC_MSG_RESULT(no) + else + AC_MSG_RESULT(yes) + LIBS="$LIBS -lssl -lcrypto"; + LDFLAGS="$LDFLAGS -L$ssldir/lib"; + HAVE_SSL="yes"; + AC_SUBST(HAVE_SSL) + fi + ], + AC_MSG_NOTICE([ssl support disabled]) +)], +[ + AC_MSG_CHECKING([for OpenSSL]) + for dir in /usr/local/ssl /usr/lib/ssl /usr/ssl /usr/pkg /usr/local /usr; do + ssldir="$dir" + if test -f "$dir/include/openssl/ssl.h"; then + found_ssl="yes"; + CFLAGS="$CFLAGS -I$ssldir/include/"; + break; + fi + if test -f "$dir/include/ssl.h"; then + found_ssl="yes"; + CFLAGS="$CFLAGS -I$ssldir/include/"; + break; + fi + done + if test x_$found_ssl != x_yes; then + AC_MSG_RESULT(no) + else + AC_MSG_RESULT(yes) + LIBS="$LIBS -lssl -lcrypto"; + LDFLAGS="$LDFLAGS -L$ssldir/lib"; + HAVE_SSL="yes"; + AC_SUBST(HAVE_SSL) + fi +]) +]) + +# =========================================================================== +# http://autoconf-archive.cryp.to/type_socklen_t.html +# =========================================================================== +# +# SYNOPSIS +# +# TYPE_SOCKLEN_T +# +# DESCRIPTION +# +# Check whether sys/socket.h defines type socklen_t. Please note that some +# systems require sys/types.h to be included before sys/socket.h can be +# compiled. +# +# LAST MODIFICATION +# +# 2008-04-12 +# +# COPYLEFT +# +# Copyright (c) 2008 Lars Brinkhoff +# +# This program 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 of the License, or (at your +# option) any later version. +# +# This program 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 this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Macro Archive. When you make and +# distribute a modified version of the Autoconf Macro, you may extend this +# special exception to the GPL to apply to your modified version as well. + +AC_DEFUN([TYPE_SOCKLEN_T], +[AC_CACHE_CHECK([for socklen_t], ac_cv_type_socklen_t, +[ + AC_TRY_COMPILE( + [#include + #include ], + [socklen_t len = 42; return 0;], + ac_cv_type_socklen_t=yes, + ac_cv_type_socklen_t=no) +]) + if test $ac_cv_type_socklen_t != yes; then + AC_DEFINE(socklen_t, int, [Substitute for socklen_t]) + fi +]) + +# =========================================================================== +# http://autoconf-archive.cryp.to/lib_socket_nsl.html +# =========================================================================== +# +# SYNOPSIS +# +# LIB_SOCKET_NSL +# +# DESCRIPTION +# +# This macro figures out what libraries are required on this platform to +# link sockets programs. +# +# The common cases are not to need any extra libraries, or to need +# -lsocket and -lnsl. We need to avoid linking with libnsl unless we need +# it, though, since on some OSes where it isn't necessary it will totally +# break networking. Unisys also includes gethostbyname() in libsocket but +# needs libnsl for socket(). +# +# LAST MODIFICATION +# +# 2008-04-12 +# +# COPYLEFT +# +# Copyright (c) 2008 Russ Allbery +# Copyright (c) 2008 Stepan Kasal +# Copyright (c) 2008 Warren Young +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. + +AC_DEFUN([LIB_SOCKET_NSL], +[ + AC_SEARCH_LIBS([gethostbyname], [nsl]) + AC_SEARCH_LIBS([socket], [socket], [], [ + AC_CHECK_LIB([socket], [socket], [LIBS="-lsocket -lnsl $LIBS"], + [], [-lnsl])]) +]) + + +# =========================================================================== +# http://autoconf-archive.cryp.to/ac_func_snprintf.html +# =========================================================================== +# +# SYNOPSIS +# +# AC_FUNC_SNPRINTF +# +# DESCRIPTION +# +# Checks for a fully C99 compliant snprintf, in particular checks whether +# it does bounds checking and returns the correct string length; does the +# same check for vsnprintf. If no working snprintf or vsnprintf is found, +# request a replacement and warn the user about it. Note: the mentioned +# replacement is freely available and may be used in any project +# regardless of it's license. +# +# LAST MODIFICATION +# +# 2008-04-12 +# +# COPYLEFT +# +# Copyright (c) 2008 Rüdiger Kuhlmann +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. + +AC_DEFUN([AC_FUNC_SNPRINTF], +[AC_CHECK_FUNCS(snprintf vsnprintf) +AC_MSG_CHECKING(for working snprintf) +AC_CACHE_VAL(ac_cv_have_working_snprintf, +[AC_TRY_RUN( +[#include + +int main(void) +{ + char bufs[5] = { 'x', 'x', 'x', '\0', '\0' }; + char bufd[5] = { 'x', 'x', 'x', '\0', '\0' }; + int i; + i = snprintf (bufs, 2, "%s", "111"); + if (strcmp (bufs, "1")) exit (1); + if (i != 3) exit (1); + i = snprintf (bufd, 2, "%d", 111); + if (strcmp (bufd, "1")) exit (1); + if (i != 3) exit (1); + exit(0); +}], ac_cv_have_working_snprintf=yes, ac_cv_have_working_snprintf=no, ac_cv_have_working_snprintf=cross)]) +AC_MSG_RESULT([$ac_cv_have_working_snprintf]) +AC_MSG_CHECKING(for working vsnprintf) +AC_CACHE_VAL(ac_cv_have_working_vsnprintf, +[AC_TRY_RUN( +[#include +#include + +int my_vsnprintf (char *buf, const char *tmpl, ...) +{ + int i; + va_list args; + va_start (args, tmpl); + i = vsnprintf (buf, 2, tmpl, args); + va_end (args); + return i; +} + +int main(void) +{ + char bufs[5] = { 'x', 'x', 'x', '\0', '\0' }; + char bufd[5] = { 'x', 'x', 'x', '\0', '\0' }; + int i; + i = my_vsnprintf (bufs, "%s", "111"); + if (strcmp (bufs, "1")) exit (1); + if (i != 3) exit (1); + i = my_vsnprintf (bufd, "%d", 111); + if (strcmp (bufd, "1")) exit (1); + if (i != 3) exit (1); + exit(0); +}], ac_cv_have_working_vsnprintf=yes, ac_cv_have_working_vsnprintf=no, ac_cv_have_working_vsnprintf=cross)]) +AC_MSG_RESULT([$ac_cv_have_working_vsnprintf]) +if test x$ac_cv_have_working_snprintf$ac_cv_have_working_vsnprintf != "xyesyes"; then + AC_LIBOBJ(snprintf) + AC_MSG_WARN([Replacing missing/broken (v)snprintf() with version from http://www.ijs.si/software/snprintf/.]) + AC_DEFINE(PREFER_PORTABLE_SNPRINTF, 1, "enable replacement (v)snprintf if system (v)snprintf is broken") +fi]) + +# =========================================================================== +# http://autoconf-archive.cryp.to/ax_lib_postgresql.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_LIB_POSTGRESQL([MINIMUM-VERSION]) +# +# DESCRIPTION +# +# This macro provides tests of availability of PostgreSQL 'libpq' library +# of particular version or newer. +# +# AX_LIB_POSTGRESQL macro takes only one argument which is optional. If +# there is no required version passed, then macro does not run version +# test. +# +# The --with-postgresql option takes one of three possible values: +# +# no - do not check for PostgreSQL client library +# +# yes - do check for PostgreSQL library in standard locations (pg_config +# should be in the PATH) +# +# path - complete path to pg_config utility, use this option if pg_config +# can't be found in the PATH +# +# This macro calls: +# +# AC_SUBST(POSTGRESQL_CFLAGS) +# AC_SUBST(POSTGRESQL_LDFLAGS) +# AC_SUBST(POSTGRESQL_VERSION) +# +# And sets: +# +# HAVE_POSTGRESQL +# +# LAST MODIFICATION +# +# 2008-04-12 +# +# COPYLEFT +# +# Copyright (c) 2008 Mateusz Loskot +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. + +AC_DEFUN([AX_LIB_POSTGRESQL], +[ + AC_ARG_WITH([postgresql], + AC_HELP_STRING([--with-postgresql=@<:@ARG@:>@], + [use PostgreSQL library @<:@default=yes@:>@, optionally specify path to pg_config] + ), + [ + if test "$withval" = "no"; then + want_postgresql="no" + elif test "$withval" = "yes"; then + want_postgresql="yes" + else + want_postgresql="yes" + PG_CONFIG="$withval" + fi + ], + [want_postgresql="yes"] + ) + + POSTGRESQL_CFLAGS="" + POSTGRESQL_LDFLAGS="" + POSTGRESQL_VERSION="" + + dnl + dnl Check PostgreSQL libraries (libpq) + dnl + + if test "$want_postgresql" = "yes"; then + + if test -z "$PG_CONFIG" -o test; then + AC_PATH_PROG([PG_CONFIG], [pg_config], []) + fi + + if test ! -x "$PG_CONFIG"; then + PG_CONFIG="no" + found_postgresql="no" + fi + + if test "$PG_CONFIG" != "no"; then + AC_MSG_CHECKING([for PostgreSQL libraries]) + + POSTGRESQL_CFLAGS="-I`$PG_CONFIG --includedir`" + POSTGRESQL_LDFLAGS="-L`$PG_CONFIG --libdir` -lpq" + + POSTGRESQL_VERSION=`$PG_CONFIG --version | sed -e 's#PostgreSQL ##'` + + AC_DEFINE([HAVE_POSTGRESQL], [1], + [Define to 1 if PostgreSQL libraries are available]) + + found_postgresql="yes" + AC_MSG_RESULT([yes]) + else + found_postgresql="no" +dnl AC_MSG_RESULT([no]) + fi + fi + + dnl + dnl Check if required version of PostgreSQL is available + dnl + + + postgresql_version_req=ifelse([$1], [], [], [$1]) + + if test "$found_postgresql" = "yes" -a -n "$postgresql_version_req"; then + + AC_MSG_CHECKING([if PostgreSQL version is >= $postgresql_version_req]) + + dnl Decompose required version string of PostgreSQL + dnl and calculate its number representation + postgresql_version_req_major=`expr $postgresql_version_req : '\([[0-9]]*\)'` + postgresql_version_req_minor=`expr $postgresql_version_req : '[[0-9]]*\.\([[0-9]]*\)'` + postgresql_version_req_micro=`expr $postgresql_version_req : '[[0-9]]*\.[[0-9]]*\.\([[0-9]]*\)'` + if test "x$postgresql_version_req_micro" = "x"; then + postgresql_version_req_micro="0" + fi + + postgresql_version_req_number=`expr $postgresql_version_req_major \* 1000000 \ + \+ $postgresql_version_req_minor \* 1000 \ + \+ $postgresql_version_req_micro` + + dnl Decompose version string of installed PostgreSQL + dnl and calculate its number representation + postgresql_version_major=`expr $POSTGRESQL_VERSION : '\([[0-9]]*\)'` + postgresql_version_minor=`expr $POSTGRESQL_VERSION : '[[0-9]]*\.\([[0-9]]*\)'` + postgresql_version_micro=`expr $POSTGRESQL_VERSION : '[[0-9]]*\.[[0-9]]*\.\([[0-9]]*\)'` + if test "x$postgresql_version_micro" = "x"; then + postgresql_version_micro="0" + fi + + postgresql_version_number=`expr $postgresql_version_major \* 1000000 \ + \+ $postgresql_version_minor \* 1000 \ + \+ $postgresql_version_micro` + + postgresql_version_check=`expr $postgresql_version_number \>\= $postgresql_version_req_number` + if test "$postgresql_version_check" = "1"; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + fi + fi + + AC_SUBST([POSTGRESQL_VERSION]) + AC_SUBST([POSTGRESQL_CFLAGS]) + AC_SUBST([POSTGRESQL_LDFLAGS]) +]) + + +# =========================================================================== +# http://autoconf-archive.cryp.to/ax_lib_sqlite3.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_LIB_SQLITE3([MINIMUM-VERSION]) +# +# DESCRIPTION +# +# Test for the SQLite 3 library of a particular version (or newer) +# +# This macro takes only one optional argument, required version of SQLite +# 3 library. If required version is not passed, 3.0.0 is used in the test +# of existance of SQLite 3. +# +# If no intallation prefix to the installed SQLite library is given the +# macro searches under /usr, /usr/local, and /opt. +# +# This macro calls: +# +# AC_SUBST(SQLITE3_CFLAGS) +# AC_SUBST(SQLITE3_LDFLAGS) +# AC_SUBST(SQLITE3_VERSION) +# +# And sets: +# +# HAVE_SQLITE3 +# +# LAST MODIFICATION +# +# 2008-04-12 +# +# COPYLEFT +# +# Copyright (c) 2008 Mateusz Loskot +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. + +AC_DEFUN([AX_LIB_SQLITE3], +[ + AC_ARG_WITH([sqlite3], + AC_HELP_STRING( + [--with-sqlite3=@<:@ARG@:>@], + [use SQLite 3 library @<:@default=yes@:>@, optionally specify the prefix for sqlite3 library] + ), + [ + if test "$withval" = "no"; then + WANT_SQLITE3="no" + elif test "$withval" = "yes"; then + WANT_SQLITE3="yes" + ac_sqlite3_path="" + else + WANT_SQLITE3="yes" + ac_sqlite3_path="$withval" + fi + ], + [WANT_SQLITE3="yes"] + ) + + SQLITE3_CFLAGS="" + SQLITE3_LDFLAGS="" + SQLITE3_VERSION="" + + if test "x$WANT_SQLITE3" = "xyes"; then + + ac_sqlite3_header="sqlite3.h" + + sqlite3_version_req=ifelse([$1], [], [3.0.0], [$1]) + sqlite3_version_req_shorten=`expr $sqlite3_version_req : '\([[0-9]]*\.[[0-9]]*\)'` + sqlite3_version_req_major=`expr $sqlite3_version_req : '\([[0-9]]*\)'` + sqlite3_version_req_minor=`expr $sqlite3_version_req : '[[0-9]]*\.\([[0-9]]*\)'` + sqlite3_version_req_micro=`expr $sqlite3_version_req : '[[0-9]]*\.[[0-9]]*\.\([[0-9]]*\)'` + if test "x$sqlite3_version_req_micro" = "x" ; then + sqlite3_version_req_micro="0" + fi + + sqlite3_version_req_number=`expr $sqlite3_version_req_major \* 1000000 \ + \+ $sqlite3_version_req_minor \* 1000 \ + \+ $sqlite3_version_req_micro` + + AC_MSG_CHECKING([for SQLite3 library >= $sqlite3_version_req]) + + if test "$ac_sqlite3_path" != ""; then + ac_sqlite3_ldflags="-L$ac_sqlite3_path/lib" + ac_sqlite3_cppflags="-I$ac_sqlite3_path/include" + else + for ac_sqlite3_path_tmp in /usr /usr/local /opt ; do + if test -f "$ac_sqlite3_path_tmp/include/$ac_sqlite3_header" \ + && test -r "$ac_sqlite3_path_tmp/include/$ac_sqlite3_header"; then + ac_sqlite3_path=$ac_sqlite3_path_tmp + ac_sqlite3_cppflags="-I$ac_sqlite3_path_tmp/include" + ac_sqlite3_ldflags="-L$ac_sqlite3_path_tmp/lib" + break; + fi + done + fi + + ac_sqlite3_ldflags="$ac_sqlite3_ldflags -lsqlite3" + + saved_CPPFLAGS="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS $ac_sqlite3_cppflags" + + AC_COMPILE_IFELSE( + [ + AC_LANG_PROGRAM([[@%:@include ]], + [[ +#if (SQLITE_VERSION_NUMBER >= $sqlite3_version_req_number) +/* Everything is okay */ +#else +# error SQLite version is too old +#endif + ]] + ) + ], + [ + AC_MSG_RESULT([yes]) + success="yes" + ], + [ + AC_MSG_RESULT([not found]) + succees="no" + ] + ) + + CPPFLAGS="$saved_CPPFLAGS" + + if test "$success" = "yes"; then + + found_sqlite=yes + SQLITE3_CFLAGS="$ac_sqlite3_cppflags" + SQLITE3_LDFLAGS="$ac_sqlite3_ldflags" + + ac_sqlite3_header_path="$ac_sqlite3_path/include/$ac_sqlite3_header" + + dnl Retrieve SQLite release version + if test "x$ac_sqlite3_header_path" != "x"; then + ac_sqlite3_version=`cat $ac_sqlite3_header_path \ + | grep '#define.*SQLITE_VERSION.*\"' | sed -e 's/.* "//' \ + | sed -e 's/"//'` + if test $ac_sqlite3_version != ""; then + SQLITE3_VERSION=$ac_sqlite3_version + else + AC_MSG_WARN([Can not find SQLITE_VERSION macro in sqlite3.h header to retrieve SQLite version!]) + fi + fi + + AC_SUBST(SQLITE3_CFLAGS) + AC_SUBST(SQLITE3_LDFLAGS) + AC_SUBST(SQLITE3_VERSION) + AC_DEFINE([HAVE_SQLITE3], [], [Have the SQLITE3 library]) + fi + fi +]) + +# =========================================================================== +# http://autoconf-archive.cryp.to/ax_c___attribute__.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_C___ATTRIBUTE__ +# +# DESCRIPTION +# +# Provides a test for the compiler support of __attribute__ extensions. +# Defines HAVE___ATTRIBUTE__ if it is found. +# +# LAST MODIFICATION +# +# 2008-04-12 +# +# COPYLEFT +# +# Copyright (c) 2008 Stepan Kasal +# Copyright (c) 2008 Christian Haggstrom +# Copyright (c) 2008 Ryan McCabe +# +# This program 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 of the License, or (at your +# option) any later version. +# +# This program 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 this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Macro Archive. When you make and +# distribute a modified version of the Autoconf Macro, you may extend this +# special exception to the GPL to apply to your modified version as well. + +AC_DEFUN([AX_C___ATTRIBUTE__], [ + AC_CACHE_CHECK([for __attribute__], [ax_cv___attribute__], + [AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM( + [[#include + static void foo(void) __attribute__ ((unused)); + static void + foo(void) { + exit(1); + } + ]], [])], + [ax_cv___attribute__=yes], + [ax_cv___attribute__=no] + ) + ]) + if test "$ax_cv___attribute__" = "yes"; then + AC_DEFINE([HAVE___ATTRIBUTE__], 1, [define if your compiler has __attribute__]) + fi +]) + + +# =========================================================================== +# http://autoconf-archive.cryp.to/ax_gcc_malloc_call.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_GCC_MALLOC_CALL +# +# DESCRIPTION +# +# The macro will compile a test program to see whether the compiler does +# understand the per-function postfix pragma. +# +# LAST MODIFICATION +# +# 2008-04-12 +# +# COPYLEFT +# +# Copyright (c) 2008 Guido U. Draheim +# +# This program 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 of the License, or (at your +# option) any later version. +# +# This program 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 this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Macro Archive. When you make and +# distribute a modified version of the Autoconf Macro, you may extend this +# special exception to the GPL to apply to your modified version as well. + +AC_DEFUN([AX_GCC_MALLOC_CALL],[dnl +AC_CACHE_CHECK( + [whether the compiler supports function __attribute__((__malloc__))], + ax_cv_gcc_malloc_call,[ + AC_TRY_COMPILE([__attribute__((__malloc__)) + int f(int i) { return i; }], + [], + ax_cv_gcc_malloc_call=yes, ax_cv_gcc_malloc_call=no)]) + if test "$ax_cv_gcc_malloc_call" = yes; then + AC_DEFINE([GCC_MALLOC_CALL],[__attribute__((__malloc__))], + [most gcc compilers know a function __attribute__((__malloc__))]) + fi +]) + + +# =========================================================================== +# http://autoconf-archive.cryp.to/ax_gcc_option.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_GCC_OPTION(OPTION,EXTRA-OPTIONS,TEST-PROGRAM,ACTION-IF-SUCCESSFUL,ACTION-IF-NOT-SUCCESFUL) +# +# DESCRIPTION +# +# AX_GCC_OPTION checks wheter gcc accepts the passed OPTION. If it accepts +# the OPTION then ACTION-IF-SUCCESSFUL will be executed, otherwise +# ACTION-IF-UNSUCCESSFUL. +# +# NOTE: This macro will be obsoleted by AX_C_CHECK_FLAG AX_CXX_CHECK_FLAG, +# AX_CPP_CHECK_FLAG, AX_CXXCPP_CHECK_FLAG and AX_LD_CHECK_FLAG. +# +# A typical usage should be the following one: +# +# AX_GCC_OPTION([-fomit-frame-pointer],[],[],[ +# AC_MSG_NOTICE([The option is supported])],[ +# AC_MSG_NOTICE([No luck this time]) +# ]) +# +# The macro doesn't discriminate between languages so, if you are testing +# for an option that works for C++ but not for C you should use '-x c++' +# as EXTRA-OPTIONS: +# +# AX_GCC_OPTION([-fno-rtti],[-x c++],[],[ ... ],[ ... ]) +# +# OPTION is tested against the following code: +# +# int main() +# { +# return 0; +# } +# +# The optional TEST-PROGRAM comes handy when the default main() is not +# suited for the option being checked +# +# So, if you need to test for -fstrict-prototypes option you should +# probably use the macro as follows: +# +# AX_GCC_OPTION([-fstrict-prototypes],[-x c++],[ +# int main(int argc, char ** argv) +# { +# (void) argc; +# (void) argv; +# +# return 0; +# } +# ],[ ... ],[ ... ]) +# +# Note that the macro compiles but doesn't link the test program so it is +# not suited for checking options that are passed to the linker, like: +# +# -Wl,-L +# +# In order to avoid such kind of problems you should think about usinguse +# the AX_*_CHECK_FLAG family macros +# +# LAST MODIFICATION +# +# 2008-04-12 +# +# COPYLEFT +# +# Copyright (c) 2008 Francesco Salvestrini +# Copyright (c) 2008 Bogdan Drozdowski +# +# This program 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 of the License, or (at your +# option) any later version. +# +# This program 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 this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Macro Archive. When you make and +# distribute a modified version of the Autoconf Macro, you may extend this +# special exception to the GPL to apply to your modified version as well. + +AC_DEFUN([AX_GCC_OPTION], [ + AC_REQUIRE([AC_PROG_CC]) + + AC_MSG_CHECKING([if gcc accepts $1 option]) + + AS_IF([ test "x$GCC" = "xyes" ],[ + AS_IF([ test -z "$3" ],[ + ax_gcc_option_test="int main() +{ + return 0; +}" + ],[ + ax_gcc_option_test="$3" + ]) + + # Dump the test program to file + cat < conftest.c +$ax_gcc_option_test +EOF + + # Dump back the file to the log, useful for debugging purposes + AC_TRY_COMMAND(cat conftest.c 1>&AS_MESSAGE_LOG_FD) + + AS_IF([ AC_TRY_COMMAND($CC $2 $1 -c conftest.c 1>&AS_MESSAGE_LOG_FD) ],[ + AC_MSG_RESULT([yes]) + $4 + ],[ + AC_MSG_RESULT([no]) + $5 + ]) + ],[ + AC_MSG_RESULT([no gcc available]) + ]) +]) + +# =========================================================================== +# http://autoconf-archive.cryp.to/ax_with_perl.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_WITH_PERL([VALUE-IF-NOT-FOUND],[PATH]) +# +# DESCRIPTION +# +# Locates an installed Perl binary, placing the result in the precious +# variable $PERL. Accepts a present $PERL, then --with-perl, and failing +# that searches for perl in the given path (which defaults to the system +# path). If perl is found, $PERL is set to the full path of the binary; if +# it is not found $PERL is set to VALUE-IF-NOT-FOUND if provided, +# unchanged otherwise. +# +# A typical use could be the following one: +# +# AX_WITH_PERL +# +# LAST MODIFICATION +# +# 2008-05-05 +# +# COPYLEFT +# +# Copyright (c) 2008 Francesco Salvestrini +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. + +AC_DEFUN([AX_WITH_PERL],[ + AX_WITH_PROG(PERL,perl,$1,$2) +]) +# =========================================================================== +# http://autoconf-archive.cryp.to/ax_with_prog.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_WITH_PROG([VARIABLE],[program],[VALUE-IF-NOT-FOUND],[PATH]) +# +# DESCRIPTION +# +# Locates an installed program binary, placing the result in the precious +# variable VARIABLE. Accepts a present VARIABLE, then --with-program, and +# failing that searches for program in the given path (which defaults to +# the system path). If program is found, VARIABLE is set to the full path +# of the binary; if it is not found VARIABLE is set to VALUE-IF-NOT-FOUND +# if provided, unchanged otherwise. +# +# A typical example could be the following one: +# +# AX_WITH_PROG(PERL,perl) +# +# NOTE: This macro is based upon the original AX_WITH_PYTHON macro from +# Dustin J. Mitchell . +# +# LAST MODIFICATION +# +# 2008-05-05 +# +# COPYLEFT +# +# Copyright (c) 2008 Francesco Salvestrini +# Copyright (c) 2008 Dustin J. Mitchell +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. + +AC_DEFUN([AX_WITH_PROG],[ + AC_PREREQ([2.61]) + + pushdef([VARIABLE],$1) + pushdef([EXECUTABLE],$2) + pushdef([VALUE_IF_NOT_FOUND],$3) + pushdef([PATH_PROG],$4) + + AC_ARG_VAR(VARIABLE,Absolute path to EXECUTABLE executable) + + AS_IF(test -z "$VARIABLE",[ + AC_MSG_CHECKING(whether EXECUTABLE executable path has been provided) + AC_ARG_WITH(EXECUTABLE,AS_HELP_STRING([--with-EXECUTABLE=[[[[PATH]]]]],absolute path to EXECUTABLE executable), [ + AS_IF([test "$withval" != "yes"],[ + VARIABLE="$withval" + AC_MSG_RESULT($VARIABLE) + ],[ + VARIABLE="" + AC_MSG_RESULT([no]) + ]) + ],[ + AC_MSG_RESULT([no]) + ]) + + AS_IF(test -z "$VARIABLE",[ + AC_PATH_PROG([]VARIABLE[],[]EXECUTABLE[],[]VALUE_IF_NOT_FOUND[],[]PATH_PROG[]) + ]) + ]) + + popdef([PATH_PROG]) + popdef([VALUE_IF_NOT_FOUND]) + popdef([EXECUTABLE]) + popdef([VARIABLE]) +]) + +# =========================================================================== +# http://autoconf-archive.cryp.to/ax_path_lib_pcre.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_PATH_LIB_PCRE [(A/NA)] +# +# DESCRIPTION +# +# check for pcre lib and set PCRE_LIBS and PCRE_CFLAGS accordingly. +# +# also provide --with-pcre option that may point to the $prefix of the +# pcre installation - the macro will check $pcre/include and $pcre/lib to +# contain the necessary files. +# +# the usual two ACTION-IF-FOUND / ACTION-IF-NOT-FOUND are supported and +# they can take advantage of the LIBS/CFLAGS additions. +# +# LAST MODIFICATION +# +# 2008-04-12 +# +# COPYLEFT +# +# Copyright (c) 2008 Guido U. Draheim +# +# This program 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 of the License, or (at your +# option) any later version. +# +# This program 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 this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Macro Archive. When you make and +# distribute a modified version of the Autoconf Macro, you may extend this +# special exception to the GPL to apply to your modified version as well. + +AC_DEFUN([AX_PATH_LIB_PCRE],[dnl +AC_MSG_CHECKING([lib pcre]) +AC_ARG_WITH(pcre, +AS_HELP_STRING([--with-pcre], [Use system pcre]),, + with_pcre="yes") +if test ".$with_pcre" = ".no" ; then + AC_MSG_RESULT([disabled]) + m4_ifval($2,$2) +else + AC_MSG_RESULT([(testing)]) + AC_CHECK_LIB(pcre, pcre_study) + if test "$ac_cv_lib_pcre_pcre_study" = "yes" ; then + PCRE_LIBS="-lpcre" + AC_MSG_CHECKING([lib pcre]) + AC_MSG_RESULT([$PCRE_LIBS]) + m4_ifval($1,$1) + else + OLDLDFLAGS="$LDFLAGS" ; LDFLAGS="$LDFLAGS -L$with_pcre/lib" + OLDCPPFLAGS="$CPPFLAGS" ; CPPFLAGS="$CPPFLAGS -I$with_pcre/include" + AC_CHECK_LIB(pcre, pcre_compile) + CPPFLAGS="$OLDCPPFLAGS" + LDFLAGS="$OLDLDFLAGS" + if test "$ac_cv_lib_pcre_pcre_compile" = "yes" ; then + AC_MSG_RESULT(.setting PCRE_LIBS -L$with_pcre/lib -lpcre) + PCRE_LIBS="-L$with_pcre/lib -lpcre" + test -d "$with_pcre/include" && PCRE_CFLAGS="-I$with_pcre/include" + AC_MSG_CHECKING([lib pcre]) + AC_MSG_RESULT([$PCRE_LIBS]) + m4_ifval($1,$1) + else + AC_MSG_CHECKING([lib pcre]) + AC_MSG_RESULT([no, (WARNING)]) + m4_ifval($2,$2) + fi + fi +fi +AC_SUBST([PCRE_LIBS]) +AC_SUBST([PCRE_CFLAGS]) +]) +# =========================================================================== +# http://autoconf-archive.cryp.to/ax_ld_check_flag.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_LD_CHECK_FLAG(FLAG-TO-CHECK,[PROLOGUE],[BODY],[ACTION-IF-SUCCESS],[ACTION-IF-FAILURE]) +# +# DESCRIPTION +# +# This macro tests if the C++ compiler supports the flag FLAG-TO-CHECK. If +# successfull execute ACTION-IF-SUCCESS otherwise ACTION-IF-FAILURE. +# PROLOGUE and BODY are optional and should be used as in AC_LANG_PROGRAM +# macro. +# +# Example: +# +# AX_LD_CHECK_FLAG([-Wl,-L/usr/lib],[],[],[ +# ... +# ],[ +# ... +# ]) +# +# This code is inspired from KDE_CHECK_COMPILER_FLAG macro. Thanks to +# Bogdan Drozdowski for testing and bug fixes. +# +# LAST MODIFICATION +# +# 2008-04-12 +# +# COPYLEFT +# +# Copyright (c) 2008 Francesco Salvestrini +# +# This program 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 of the License, or (at your +# option) any later version. +# +# This program 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 this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Macro Archive. When you make and +# distribute a modified version of the Autoconf Macro, you may extend this +# special exception to the GPL to apply to your modified version as well. + +AC_DEFUN([AX_LD_CHECK_FLAG],[ + AC_PREREQ([2.61]) + AC_REQUIRE([AC_PROG_CXX]) + AC_REQUIRE([AC_PROG_SED]) + + flag=`echo "$1" | $SED 'y% .=/+-(){}<>:*,%_______________%'` + + AC_CACHE_CHECK([whether the linker accepts the $1 flag], + [ax_cv_ld_check_flag_$flag],[ + + #AC_LANG_PUSH([C]) + + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $1" + AC_LINK_IFELSE([ + AC_LANG_PROGRAM([$2],[$3]) + ],[ + eval "ax_cv_ld_check_flag_$flag=yes" + ],[ + eval "ax_cv_ld_check_flag_$flag=no" + ]) + + LDFLAGS="$save_LDFLAGS" + + #AC_LANG_POP + + ]) + + AS_IF([eval "test \"`echo '$ax_cv_ld_check_flag_'$flag`\" = yes"],[ + : + $4 + ],[ + : + $5 + ]) +]) diff --git a/config.guess b/config.guess new file mode 100644 index 0000000..396482d --- /dev/null +++ b/config.guess @@ -0,0 +1,1500 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, +# Inc. + +timestamp='2006-07-02' + +# This file 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 of the License, or +# (at your option) any later version. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA +# 02110-1301, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + + +# Originally written by Per Bothner . +# Please send patches to . Submit a context +# diff and a properly formatted ChangeLog entry. +# +# This script attempts to guess a canonical system name similar to +# config.sub. If it succeeds, it prints the system name on stdout, and +# exits with 0. Otherwise, it exits with 1. +# +# The plan is that this can be called by configure scripts if you +# don't specify an explicit build system type. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] + +Output the configuration name of the system \`$me' is run on. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.guess ($timestamp) + +Originally written by Per Bothner. +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 +Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" >&2 + exit 1 ;; + * ) + break ;; + esac +done + +if test $# != 0; then + echo "$me: too many arguments$help" >&2 + exit 1 +fi + +trap 'exit 1' 1 2 15 + +# CC_FOR_BUILD -- compiler used by this script. Note that the use of a +# compiler to aid in system detection is discouraged as it requires +# temporary files to be created and, as you can see below, it is a +# headache to deal with in a portable fashion. + +# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still +# use `HOST_CC' if defined, but it is deprecated. + +# Portable tmp directory creation inspired by the Autoconf team. + +set_cc_for_build=' +trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; +trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; +: ${TMPDIR=/tmp} ; + { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || + { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || + { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || + { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; +dummy=$tmp/dummy ; +tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; +case $CC_FOR_BUILD,$HOST_CC,$CC in + ,,) echo "int x;" > $dummy.c ; + for c in cc gcc c89 c99 ; do + if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then + CC_FOR_BUILD="$c"; break ; + fi ; + done ; + if test x"$CC_FOR_BUILD" = x ; then + CC_FOR_BUILD=no_compiler_found ; + fi + ;; + ,,*) CC_FOR_BUILD=$CC ;; + ,*,*) CC_FOR_BUILD=$HOST_CC ;; +esac ; set_cc_for_build= ;' + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 1994-08-24) +if (test -f /.attbin/uname) >/dev/null 2>&1 ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +# Note: order is significant - the case branches are not exclusive. + +case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in + *:NetBSD:*:*) + # NetBSD (nbsd) targets should (where applicable) match one or + # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, + # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently + # switched to ELF, *-*-netbsd* would select the old + # object file format. This provides both forward + # compatibility and a consistent mechanism for selecting the + # object file format. + # + # Note: NetBSD doesn't particularly care about the vendor + # portion of the name. We always set it to "unknown". + sysctl="sysctl -n hw.machine_arch" + UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ + /usr/sbin/$sysctl 2>/dev/null || echo unknown)` + case "${UNAME_MACHINE_ARCH}" in + armeb) machine=armeb-unknown ;; + arm*) machine=arm-unknown ;; + sh3el) machine=shl-unknown ;; + sh3eb) machine=sh-unknown ;; + *) machine=${UNAME_MACHINE_ARCH}-unknown ;; + esac + # The Operating System including object format, if it has switched + # to ELF recently, or will in the future. + case "${UNAME_MACHINE_ARCH}" in + arm*|i386|m68k|ns32k|sh3*|sparc|vax) + eval $set_cc_for_build + if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep __ELF__ >/dev/null + then + # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). + # Return netbsd for either. FIX? + os=netbsd + else + os=netbsdelf + fi + ;; + *) + os=netbsd + ;; + esac + # The OS release + # Debian GNU/NetBSD machines have a different userland, and + # thus, need a distinct triplet. However, they do not need + # kernel version information, so it can be replaced with a + # suitable tag, in the style of linux-gnu. + case "${UNAME_VERSION}" in + Debian*) + release='-gnu' + ;; + *) + release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + ;; + esac + # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: + # contains redundant information, the shorter form: + # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. + echo "${machine}-${os}${release}" + exit ;; + *:OpenBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} + exit ;; + *:ekkoBSD:*:*) + echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} + exit ;; + *:SolidBSD:*:*) + echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} + exit ;; + macppc:MirBSD:*:*) + echo powerpc-unknown-mirbsd${UNAME_RELEASE} + exit ;; + *:MirBSD:*:*) + echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} + exit ;; + alpha:OSF1:*:*) + case $UNAME_RELEASE in + *4.0) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + ;; + *5.*) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` + ;; + esac + # According to Compaq, /usr/sbin/psrinfo has been available on + # OSF/1 and Tru64 systems produced since 1995. I hope that + # covers most systems running today. This code pipes the CPU + # types through head -n 1, so we only detect the type of CPU 0. + ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` + case "$ALPHA_CPU_TYPE" in + "EV4 (21064)") + UNAME_MACHINE="alpha" ;; + "EV4.5 (21064)") + UNAME_MACHINE="alpha" ;; + "LCA4 (21066/21068)") + UNAME_MACHINE="alpha" ;; + "EV5 (21164)") + UNAME_MACHINE="alphaev5" ;; + "EV5.6 (21164A)") + UNAME_MACHINE="alphaev56" ;; + "EV5.6 (21164PC)") + UNAME_MACHINE="alphapca56" ;; + "EV5.7 (21164PC)") + UNAME_MACHINE="alphapca57" ;; + "EV6 (21264)") + UNAME_MACHINE="alphaev6" ;; + "EV6.7 (21264A)") + UNAME_MACHINE="alphaev67" ;; + "EV6.8CB (21264C)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8AL (21264B)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8CX (21264D)") + UNAME_MACHINE="alphaev68" ;; + "EV6.9A (21264/EV69A)") + UNAME_MACHINE="alphaev69" ;; + "EV7 (21364)") + UNAME_MACHINE="alphaev7" ;; + "EV7.9 (21364A)") + UNAME_MACHINE="alphaev79" ;; + esac + # A Pn.n version is a patched version. + # A Vn.n version is a released version. + # A Tn.n version is a released field test version. + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + exit ;; + Alpha\ *:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # Should we change UNAME_MACHINE based on the output of uname instead + # of the specific Alpha model? + echo alpha-pc-interix + exit ;; + 21064:Windows_NT:50:3) + echo alpha-dec-winnt3.5 + exit ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-unknown-sysv4 + exit ;; + *:[Aa]miga[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-amigaos + exit ;; + *:[Mm]orph[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-morphos + exit ;; + *:OS/390:*:*) + echo i370-ibm-openedition + exit ;; + *:z/VM:*:*) + echo s390-ibm-zvmoe + exit ;; + *:OS400:*:*) + echo powerpc-ibm-os400 + exit ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit ;; + arm:riscos:*:*|arm:RISCOS:*:*) + echo arm-unknown-riscos + exit ;; + SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit ;; + Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) + # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + if test "`(/bin/universe) 2>/dev/null`" = att ; then + echo pyramid-pyramid-sysv3 + else + echo pyramid-pyramid-bsd + fi + exit ;; + NILE*:*:*:dcosx) + echo pyramid-pyramid-svr4 + exit ;; + DRS?6000:unix:4.0:6*) + echo sparc-icl-nx6 + exit ;; + DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) + case `/usr/bin/uname -p` in + sparc) echo sparc-icl-nx7; exit ;; + esac ;; + sun4H:SunOS:5.*:*) + echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + i86pc:SunOS:5.*:*) + echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:*:*) + case "`/usr/bin/arch -k`" in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` + exit ;; + sun3*:SunOS:*:*) + echo m68k-sun-sunos${UNAME_RELEASE} + exit ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 + case "`/bin/arch`" in + sun3) + echo m68k-sun-sunos${UNAME_RELEASE} + ;; + sun4) + echo sparc-sun-sunos${UNAME_RELEASE} + ;; + esac + exit ;; + aushp:SunOS:*:*) + echo sparc-auspex-sunos${UNAME_RELEASE} + exit ;; + # The situation for MiNT is a little confusing. The machine name + # can be virtually everything (everything which is not + # "atarist" or "atariste" at least should have a processor + # > m68000). The system name ranges from "MiNT" over "FreeMiNT" + # to the lowercase version "mint" (or "freemint"). Finally + # the system name "TOS" denotes a system which is actually not + # MiNT. But MiNT is downward compatible to TOS, so this should + # be no problem. + atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) + echo m68k-milan-mint${UNAME_RELEASE} + exit ;; + hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) + echo m68k-hades-mint${UNAME_RELEASE} + exit ;; + *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) + echo m68k-unknown-mint${UNAME_RELEASE} + exit ;; + m68k:machten:*:*) + echo m68k-apple-machten${UNAME_RELEASE} + exit ;; + powerpc:machten:*:*) + echo powerpc-apple-machten${UNAME_RELEASE} + exit ;; + RISC*:Mach:*:*) + echo mips-dec-mach_bsd4.3 + exit ;; + RISC*:ULTRIX:*:*) + echo mips-dec-ultrix${UNAME_RELEASE} + exit ;; + VAX*:ULTRIX*:*:*) + echo vax-dec-ultrix${UNAME_RELEASE} + exit ;; + 2020:CLIX:*:* | 2430:CLIX:*:*) + echo clipper-intergraph-clix${UNAME_RELEASE} + exit ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c +#ifdef __cplusplus +#include /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && + dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && + SYSTEM_NAME=`$dummy $dummyarg` && + { echo "$SYSTEM_NAME"; exit; } + echo mips-mips-riscos${UNAME_RELEASE} + exit ;; + Motorola:PowerMAX_OS:*:*) + echo powerpc-motorola-powermax + exit ;; + Motorola:*:4.3:PL8-*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:Power_UNIX:*:*) + echo powerpc-harris-powerunix + exit ;; + m88k:CX/UX:7*:*) + echo m88k-harris-cxux7 + exit ;; + m88k:*:4*:R4*) + echo m88k-motorola-sysv4 + exit ;; + m88k:*:3*:R3*) + echo m88k-motorola-sysv3 + exit ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] + then + if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ + [ ${TARGET_BINARY_INTERFACE}x = x ] + then + echo m88k-dg-dgux${UNAME_RELEASE} + else + echo m88k-dg-dguxbcs${UNAME_RELEASE} + fi + else + echo i586-dg-dgux${UNAME_RELEASE} + fi + exit ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + echo m88k-dolphin-sysv3 + exit ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + echo m88k-motorola-sysv3 + exit ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + echo m88k-tektronix-sysv3 + exit ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + echo m68k-tektronix-bsd + exit ;; + *:IRIX*:*:*) + echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` + exit ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id + exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i*86:AIX:*:*) + echo i386-ibm-aix + exit ;; + ia64:AIX:*:*) + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} + exit ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` + then + echo "$SYSTEM_NAME" + else + echo rs6000-ibm-aix3.2.5 + fi + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + echo rs6000-ibm-aix3.2.4 + else + echo rs6000-ibm-aix3.2 + fi + exit ;; + *:AIX:*:[45]) + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` + if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${IBM_ARCH}-ibm-aix${IBM_REV} + exit ;; + *:AIX:*:*) + echo rs6000-ibm-aix + exit ;; + ibmrt:4.4BSD:*|romp-ibm:BSD:*) + echo romp-ibm-bsd4.4 + exit ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and + echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to + exit ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + echo rs6000-bull-bosx + exit ;; + DPX/2?00:B.O.S.:*:*) + echo m68k-bull-sysv3 + exit ;; + 9000/[34]??:4.3bsd:1.*:*) + echo m68k-hp-bsd + exit ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + echo m68k-hp-bsd4.4 + exit ;; + 9000/[34678]??:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + case "${UNAME_MACHINE}" in + 9000/31? ) HP_ARCH=m68000 ;; + 9000/[34]?? ) HP_ARCH=m68k ;; + 9000/[678][0-9][0-9]) + if [ -x /usr/bin/getconf ]; then + sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` + sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` + case "${sc_cpu_version}" in + 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 + 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 + 532) # CPU_PA_RISC2_0 + case "${sc_kernel_bits}" in + 32) HP_ARCH="hppa2.0n" ;; + 64) HP_ARCH="hppa2.0w" ;; + '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 + esac ;; + esac + fi + if [ "${HP_ARCH}" = "" ]; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + + #define _HPUX_SOURCE + #include + #include + + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); + + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } +EOF + (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` + test -z "$HP_ARCH" && HP_ARCH=hppa + fi ;; + esac + if [ ${HP_ARCH} = "hppa2.0w" ] + then + eval $set_cc_for_build + + # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating + # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler + # generating 64-bit code. GNU and HP use different nomenclature: + # + # $ CC_FOR_BUILD=cc ./config.guess + # => hppa2.0w-hp-hpux11.23 + # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess + # => hppa64-hp-hpux11.23 + + if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | + grep __LP64__ >/dev/null + then + HP_ARCH="hppa2.0w" + else + HP_ARCH="hppa64" + fi + fi + echo ${HP_ARCH}-hp-hpux${HPUX_REV} + exit ;; + ia64:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + echo ia64-hp-hpux${HPUX_REV} + exit ;; + 3050*:HI-UX:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + echo unknown-hitachi-hiuxwe2 + exit ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) + echo hppa1.1-hp-bsd + exit ;; + 9000/8??:4.3bsd:*:*) + echo hppa1.0-hp-bsd + exit ;; + *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) + echo hppa1.0-hp-mpeix + exit ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) + echo hppa1.1-hp-osf + exit ;; + hp8??:OSF1:*:*) + echo hppa1.0-hp-osf + exit ;; + i*86:OSF1:*:*) + if [ -x /usr/sbin/sysversion ] ; then + echo ${UNAME_MACHINE}-unknown-osf1mk + else + echo ${UNAME_MACHINE}-unknown-osf1 + fi + exit ;; + parisc*:Lites*:*:*) + echo hppa1.1-hp-lites + exit ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + echo c1-convex-bsd + exit ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + echo c34-convex-bsd + exit ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + echo c38-convex-bsd + exit ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + echo c4-convex-bsd + exit ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*[A-Z]90:*:*:*) + echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ + -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*T3E:*:*:*) + echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*SV1:*:*:*) + echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + *:UNICOS/mp:*:*) + echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) + FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + 5000:UNIX_System_V:4.*:*) + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` + echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) + echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + exit ;; + sparc*:BSD/OS:*:*) + echo sparc-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:BSD/OS:*:*) + echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:FreeBSD:*:*) + case ${UNAME_MACHINE} in + pc98) + echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + amd64) + echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + *) + echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + esac + exit ;; + i*:CYGWIN*:*) + echo ${UNAME_MACHINE}-pc-cygwin + exit ;; + i*:MINGW*:*) + echo ${UNAME_MACHINE}-pc-mingw32 + exit ;; + i*:windows32*:*) + # uname -m includes "-pc" on this system. + echo ${UNAME_MACHINE}-mingw32 + exit ;; + i*:PW*:*) + echo ${UNAME_MACHINE}-pc-pw32 + exit ;; + x86:Interix*:[3456]*) + echo i586-pc-interix${UNAME_RELEASE} + exit ;; + EM64T:Interix*:[3456]*) + echo x86_64-unknown-interix${UNAME_RELEASE} + exit ;; + [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) + echo i${UNAME_MACHINE}-pc-mks + exit ;; + i*:Windows_NT*:* | Pentium*:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we + # UNAME_MACHINE based on the output of uname instead of i386? + echo i586-pc-interix + exit ;; + i*:UWIN*:*) + echo ${UNAME_MACHINE}-pc-uwin + exit ;; + amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) + echo x86_64-unknown-cygwin + exit ;; + p*:CYGWIN*:*) + echo powerpcle-unknown-cygwin + exit ;; + prep*:SunOS:5.*:*) + echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + *:GNU:*:*) + # the GNU system + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + exit ;; + *:GNU/*:*:*) + # other systems with GNU libc and userland + echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu + exit ;; + i*86:Minix:*:*) + echo ${UNAME_MACHINE}-pc-minix + exit ;; + arm*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + avr32*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + cris:Linux:*:*) + echo cris-axis-linux-gnu + exit ;; + crisv32:Linux:*:*) + echo crisv32-axis-linux-gnu + exit ;; + frv:Linux:*:*) + echo frv-unknown-linux-gnu + exit ;; + ia64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + m32r*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + m68*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + mips:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef mips + #undef mipsel + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=mipsel + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=mips + #else + CPU= + #endif + #endif +EOF + eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' + /^CPU/{ + s: ::g + p + }'`" + test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } + ;; + mips64:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef mips64 + #undef mips64el + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=mips64el + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=mips64 + #else + CPU= + #endif + #endif +EOF + eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' + /^CPU/{ + s: ::g + p + }'`" + test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } + ;; + or32:Linux:*:*) + echo or32-unknown-linux-gnu + exit ;; + ppc:Linux:*:*) + echo powerpc-unknown-linux-gnu + exit ;; + ppc64:Linux:*:*) + echo powerpc64-unknown-linux-gnu + exit ;; + alpha:Linux:*:*) + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in + EV5) UNAME_MACHINE=alphaev5 ;; + EV56) UNAME_MACHINE=alphaev56 ;; + PCA56) UNAME_MACHINE=alphapca56 ;; + PCA57) UNAME_MACHINE=alphapca56 ;; + EV6) UNAME_MACHINE=alphaev6 ;; + EV67) UNAME_MACHINE=alphaev67 ;; + EV68*) UNAME_MACHINE=alphaev68 ;; + esac + objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null + if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi + echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} + exit ;; + parisc:Linux:*:* | hppa:Linux:*:*) + # Look for CPU level + case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in + PA7*) echo hppa1.1-unknown-linux-gnu ;; + PA8*) echo hppa2.0-unknown-linux-gnu ;; + *) echo hppa-unknown-linux-gnu ;; + esac + exit ;; + parisc64:Linux:*:* | hppa64:Linux:*:*) + echo hppa64-unknown-linux-gnu + exit ;; + s390:Linux:*:* | s390x:Linux:*:*) + echo ${UNAME_MACHINE}-ibm-linux + exit ;; + sh64*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + sh*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + sparc:Linux:*:* | sparc64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + vax:Linux:*:*) + echo ${UNAME_MACHINE}-dec-linux-gnu + exit ;; + x86_64:Linux:*:*) + echo x86_64-unknown-linux-gnu + exit ;; + i*86:Linux:*:*) + # The BFD linker knows what the default object file format is, so + # first see if it will tell us. cd to the root directory to prevent + # problems with other programs or directories called `ld' in the path. + # Set LC_ALL=C to ensure ld outputs messages in English. + ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \ + | sed -ne '/supported targets:/!d + s/[ ][ ]*/ /g + s/.*supported targets: *// + s/ .*// + p'` + case "$ld_supported_targets" in + elf32-i386) + TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu" + ;; + a.out-i386-linux) + echo "${UNAME_MACHINE}-pc-linux-gnuaout" + exit ;; + coff-i386) + echo "${UNAME_MACHINE}-pc-linux-gnucoff" + exit ;; + "") + # Either a pre-BFD a.out linker (linux-gnuoldld) or + # one that does not give us useful --help. + echo "${UNAME_MACHINE}-pc-linux-gnuoldld" + exit ;; + esac + # Determine whether the default compiler is a.out or elf + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + #ifdef __ELF__ + # ifdef __GLIBC__ + # if __GLIBC__ >= 2 + LIBC=gnu + # else + LIBC=gnulibc1 + # endif + # else + LIBC=gnulibc1 + # endif + #else + #if defined(__INTEL_COMPILER) || defined(__PGI) || defined(__SUNPRO_C) || defined(__SUNPRO_CC) + LIBC=gnu + #else + LIBC=gnuaout + #endif + #endif + #ifdef __dietlibc__ + LIBC=dietlibc + #endif +EOF + eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' + /^LIBC/{ + s: ::g + p + }'`" + test x"${LIBC}" != x && { + echo "${UNAME_MACHINE}-pc-linux-${LIBC}" + exit + } + test x"${TENTATIVE}" != x && { echo "${TENTATIVE}"; exit; } + ;; + i*86:DYNIX/ptx:4*:*) + # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. + # earlier versions are messed up and put the nodename in both + # sysname and nodename. + echo i386-sequent-sysv4 + exit ;; + i*86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} + exit ;; + i*86:OS/2:*:*) + # If we were able to find `uname', then EMX Unix compatibility + # is probably installed. + echo ${UNAME_MACHINE}-pc-os2-emx + exit ;; + i*86:XTS-300:*:STOP) + echo ${UNAME_MACHINE}-unknown-stop + exit ;; + i*86:atheos:*:*) + echo ${UNAME_MACHINE}-unknown-atheos + exit ;; + i*86:syllable:*:*) + echo ${UNAME_MACHINE}-pc-syllable + exit ;; + i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*) + echo i386-unknown-lynxos${UNAME_RELEASE} + exit ;; + i*86:*DOS:*:*) + echo ${UNAME_MACHINE}-pc-msdosdjgpp + exit ;; + i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) + UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} + fi + exit ;; + i*86:*:5:[678]*) + # UnixWare 7.x, OpenUNIX and OpenServer 6. + case `/bin/uname -X | grep "^Machine"` in + *486*) UNAME_MACHINE=i486 ;; + *Pentium) UNAME_MACHINE=i586 ;; + *Pent*|*Celeron) UNAME_MACHINE=i686 ;; + esac + echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} + exit ;; + i*86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` + (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ + && UNAME_MACHINE=i686 + (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ + && UNAME_MACHINE=i686 + echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + else + echo ${UNAME_MACHINE}-pc-sysv32 + fi + exit ;; + pc:*:*:*) + # Left here for compatibility: + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i386. + echo i386-pc-msdosdjgpp + exit ;; + Intel:Mach:3*:*) + echo i386-pc-mach3 + exit ;; + paragon:*:*:*) + echo i860-intel-osf1 + exit ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + fi + exit ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + echo m68010-convergent-sysv + exit ;; + mc68k:UNIX:SYSTEM5:3.51m) + echo m68k-convergent-sysv + exit ;; + M680?0:D-NIX:5.3:*) + echo m68k-diab-dnix + exit ;; + M68*:*:R3V[5678]*:*) + test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; + 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4; exit; } ;; + m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) + echo m68k-unknown-lynxos${UNAME_RELEASE} + exit ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos${UNAME_RELEASE} + exit ;; + rs6000:LynxOS:2.*:*) + echo rs6000-unknown-lynxos${UNAME_RELEASE} + exit ;; + PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*) + echo powerpc-unknown-lynxos${UNAME_RELEASE} + exit ;; + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv${UNAME_RELEASE} + exit ;; + RM*:ReliantUNIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + RM*:SINIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + echo ${UNAME_MACHINE}-sni-sysv4 + else + echo ns32k-sni-sysv + fi + exit ;; + PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says + echo i586-unisys-sysv4 + exit ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit ;; + i*86:VOS:*:*) + # From Paul.Green@stratus.com. + echo ${UNAME_MACHINE}-stratus-vos + exit ;; + *:VOS:*:*) + # From Paul.Green@stratus.com. + echo hppa1.1-stratus-vos + exit ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux${UNAME_RELEASE} + exit ;; + news*:NEWS-OS:6*:*) + echo mips-sony-newsos6 + exit ;; + R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) + if [ -d /usr/nec ]; then + echo mips-nec-sysv${UNAME_RELEASE} + else + echo mips-unknown-sysv${UNAME_RELEASE} + fi + exit ;; + BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. + echo powerpc-be-beos + exit ;; + BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. + echo powerpc-apple-beos + exit ;; + BePC:BeOS:*:*) # BeOS running on Intel PC compatible. + echo i586-pc-beos + exit ;; + SX-4:SUPER-UX:*:*) + echo sx4-nec-superux${UNAME_RELEASE} + exit ;; + SX-5:SUPER-UX:*:*) + echo sx5-nec-superux${UNAME_RELEASE} + exit ;; + SX-6:SUPER-UX:*:*) + echo sx6-nec-superux${UNAME_RELEASE} + exit ;; + Power*:Rhapsody:*:*) + echo powerpc-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Rhapsody:*:*) + echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Darwin:*:*) + UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown + case $UNAME_PROCESSOR in + unknown) UNAME_PROCESSOR=powerpc ;; + esac + echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} + exit ;; + *:procnto*:*:* | *:QNX:[0123456789]*:*) + UNAME_PROCESSOR=`uname -p` + if test "$UNAME_PROCESSOR" = "x86"; then + UNAME_PROCESSOR=i386 + UNAME_MACHINE=pc + fi + echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} + exit ;; + *:QNX:*:4*) + echo i386-pc-qnx + exit ;; + NSE-?:NONSTOP_KERNEL:*:*) + echo nse-tandem-nsk${UNAME_RELEASE} + exit ;; + NSR-?:NONSTOP_KERNEL:*:*) + echo nsr-tandem-nsk${UNAME_RELEASE} + exit ;; + *:NonStop-UX:*:*) + echo mips-compaq-nonstopux + exit ;; + BS2000:POSIX*:*:*) + echo bs2000-siemens-sysv + exit ;; + DS/*:UNIX_System_V:*:*) + echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} + exit ;; + *:Plan9:*:*) + # "uname -m" is not consistent, so use $cputype instead. 386 + # is converted to i386 for consistency with other x86 + # operating systems. + if test "$cputype" = "386"; then + UNAME_MACHINE=i386 + else + UNAME_MACHINE="$cputype" + fi + echo ${UNAME_MACHINE}-unknown-plan9 + exit ;; + *:TOPS-10:*:*) + echo pdp10-unknown-tops10 + exit ;; + *:TENEX:*:*) + echo pdp10-unknown-tenex + exit ;; + KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) + echo pdp10-dec-tops20 + exit ;; + XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) + echo pdp10-xkl-tops20 + exit ;; + *:TOPS-20:*:*) + echo pdp10-unknown-tops20 + exit ;; + *:ITS:*:*) + echo pdp10-unknown-its + exit ;; + SEI:*:*:SEIUX) + echo mips-sei-seiux${UNAME_RELEASE} + exit ;; + *:DragonFly:*:*) + echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit ;; + *:*VMS:*:*) + UNAME_MACHINE=`(uname -p) 2>/dev/null` + case "${UNAME_MACHINE}" in + A*) echo alpha-dec-vms ; exit ;; + I*) echo ia64-dec-vms ; exit ;; + V*) echo vax-dec-vms ; exit ;; + esac ;; + *:XENIX:*:SysV) + echo i386-pc-xenix + exit ;; + i*86:skyos:*:*) + echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' + exit ;; + i*86:rdos:*:*) + echo ${UNAME_MACHINE}-pc-rdos + exit ;; +esac + +#echo '(No uname command or uname output not recognized.)' 1>&2 +#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 + +eval $set_cc_for_build +cat >$dummy.c < +# include +#endif +main () +{ +#if defined (sony) +#if defined (MIPSEB) + /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, + I don't know.... */ + printf ("mips-sony-bsd\n"); exit (0); +#else +#include + printf ("m68k-sony-newsos%s\n", +#ifdef NEWSOS4 + "4" +#else + "" +#endif + ); exit (0); +#endif +#endif + +#if defined (__arm) && defined (__acorn) && defined (__unix) + printf ("arm-acorn-riscix\n"); exit (0); +#endif + +#if defined (hp300) && !defined (hpux) + printf ("m68k-hp-bsd\n"); exit (0); +#endif + +#if defined (NeXT) +#if !defined (__ARCHITECTURE__) +#define __ARCHITECTURE__ "m68k" +#endif + int version; + version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; + if (version < 4) + printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); + else + printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); + exit (0); +#endif + +#if defined (MULTIMAX) || defined (n16) +#if defined (UMAXV) + printf ("ns32k-encore-sysv\n"); exit (0); +#else +#if defined (CMU) + printf ("ns32k-encore-mach\n"); exit (0); +#else + printf ("ns32k-encore-bsd\n"); exit (0); +#endif +#endif +#endif + +#if defined (__386BSD__) + printf ("i386-pc-bsd\n"); exit (0); +#endif + +#if defined (sequent) +#if defined (i386) + printf ("i386-sequent-dynix\n"); exit (0); +#endif +#if defined (ns32000) + printf ("ns32k-sequent-dynix\n"); exit (0); +#endif +#endif + +#if defined (_SEQUENT_) + struct utsname un; + + uname(&un); + + if (strncmp(un.version, "V2", 2) == 0) { + printf ("i386-sequent-ptx2\n"); exit (0); + } + if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ + printf ("i386-sequent-ptx1\n"); exit (0); + } + printf ("i386-sequent-ptx\n"); exit (0); + +#endif + +#if defined (vax) +# if !defined (ultrix) +# include +# if defined (BSD) +# if BSD == 43 + printf ("vax-dec-bsd4.3\n"); exit (0); +# else +# if BSD == 199006 + printf ("vax-dec-bsd4.3reno\n"); exit (0); +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# endif +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# else + printf ("vax-dec-ultrix\n"); exit (0); +# endif +#endif + +#if defined (alliant) && defined (i860) + printf ("i860-alliant-bsd\n"); exit (0); +#endif + + exit (1); +} +EOF + +$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + +# Apollos put the system type in the environment. + +test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } + +# Convex versions that predate uname can use getsysinfo(1) + +if [ -x /usr/convex/getsysinfo ] +then + case `getsysinfo -f cpu_type` in + c1*) + echo c1-convex-bsd + exit ;; + c2*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + c34*) + echo c34-convex-bsd + exit ;; + c38*) + echo c38-convex-bsd + exit ;; + c4*) + echo c4-convex-bsd + exit ;; + esac +fi + +cat >&2 < in order to provide the needed +information to handle your system. + +config.guess timestamp = $timestamp + +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null` + +hostinfo = `(hostinfo) 2>/dev/null` +/bin/universe = `(/bin/universe) 2>/dev/null` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` +/bin/arch = `(/bin/arch) 2>/dev/null` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` + +UNAME_MACHINE = ${UNAME_MACHINE} +UNAME_RELEASE = ${UNAME_RELEASE} +UNAME_SYSTEM = ${UNAME_SYSTEM} +UNAME_VERSION = ${UNAME_VERSION} +EOF + +exit 1 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..5aa4dc9 --- /dev/null +++ b/configure.ac @@ -0,0 +1,347 @@ +### autoconf file for CobraMUSH +### This file uses tests from the Autoconf Macro Archive. +### It is available at http://autoconf-archive.cryp.to/ +### The actual tests used are in ./aclocal.m4. DO NOT AUTO-GENERATE +### that file with aclocal. + +# this is the gnu suggested m4 macro file for lua.. doesn't work so well though + +AC_INIT(configure.ac) +AC_CONFIG_HEADERS(config.h) +AC_CANONICAL_BUILD + +if test "x$CFLAGS" = "x"; then +CFLAGS="-O" +DEFAULT_CFLAGS=yes +else +DEFAULT_CFLAGS=no +fi + +AC_LANG(C) + + +# lua +# Need to create lua detection that works.. + +# ltdl detection +dnl Enable building of the convenience library +dnl and set LIBLTDL accordingly +#AC_LIBLTDL_CONVENIENCE +dnl Substitute INCLTDL and LIBLTDL in the Makefiles +#AC_SUBST(INCLTDL) +#AC_SUBST(LIBLTDL) +dnl Check for dlopen support +#AC_LIBTOOL_DLOPEN +dnl Configure libtool +#AC_PROG_LIBTOOL +dnl Configure libltdl +#AC_CONFIG_SUBDIRS(libltdl) + +### Programs + +AC_PATH_PROG(CAT, cat) +AC_PROG_CC +AC_PROG_CC_C99 +AC_PATH_PROG(GDB, gdb) +AC_PATH_PROG(CHMOD, chmod) +AC_PATH_PROG(CP, cp) +AC_PATH_PROG(ECHO, echo) +AC_PROG_INSTALL +AC_PROG_LN_S +AC_PATH_PROG(MAKE, make) + +AX_WITH_PERL +if test "${PERL+set}" != "set"; then + AC_MSG_ERROR([perl is required to build and run PennMUSH]) +fi + +AC_PATH_PROG(TEST, test) +AC_PATH_PROG(TOUCH, touch) +AC_PATH_PROG(RM, rm) +AC_PATH_PROG(INDENT, indent) +AC_PATH_PROG(CTAGS, ctags) +AC_PATH_PROG(ETAGS, etags) +AC_PATH_PROG(EXCTAGS, exctags) + +# Set good debug and warning options if using gcc +# and custom CFLAGS aren't being used. +# Todo: Look into the warnings setting macros in the autoconf archive, +# maybe use them instead? +if test $DEFAULT_CFLAGS = yes; then + if test "${GDB+set}" = "set"; then + if test "${ac_cv_c_compiler_gnu+set}" = "set"; then +CFLAGS="-ggdb $CFLAGS -W -Wall -pedantic -Wno-comment" + else +CFLAGS="-g $CFLAGS -W" + fi + else +CFLAGS="-g $CFLAGS -W" + fi +fi + +AX_GCC_OPTION([-fstack-protector], [], [], [ + CFLAGS="$CFLAGS -fstack-protector" +], []) + +case "${build_cpu}-${build_os}" in + powerpc*-darwin*) + AX_GCC_OPTION([-mdynamic-no-pic], [], [], [ + CFLAGS="$CFLAGS -mdynamic-no-pic" + ], []) + ;; +esac + +if test "${CTAGS+set}" != "set" -a "${EXCTAGS+set}" = "set"; then + CTAGS=$EXCTAGS +fi + +if test "${ETAGS+set}" != "set" -a "${EXCTAGS+set}" = "set"; then + ETAGS="$EXCTAGS -e" +fi + +AC_PATH_PROG(UPTIME, uptime) +if test "${UPTIME+set}" = "set"; then + AC_DEFINE([HAVE_UPTIME]) + AC_DEFINE_UNQUOTED([UPTIME], "$UPTIME") +fi + +AC_ARG_VAR(SENDMAIL, Path to sendmail) +AC_PATH_PROG(SENDMAIL, sendmail) +if test "${SENDMAIL+set}" = "set"; then + AC_DEFINE([HAVE_SENDMAIL]) + AC_DEFINE_UNQUOTED([SENDMAIL], "$SENDMAIL") +fi + + +### Headers +# Usually there's no need to check for standard C89 headers. + +# is checked by this. +AC_HEADER_STDC +AC_HEADER_STDBOOL +AC_HEADER_SYS_WAIT +AC_HEADER_TIME +AC_CHECK_HEADER(sys/time.h, [AC_DEFINE(I_SYS_TIME)]) +AC_CHECK_HEADER(arpa/inet.h, [AC_DEFINE(I_ARPA_INET)]) +AC_CHECK_HEADER(arpa/nameser.h, [AC_DEFINE(I_ARPA_NAMESER)]) +AC_CHECK_HEADER(fcntl.h, [AC_DEFINE(I_FCNTL)]) +AC_CHECK_HEADER(floatingpoint.h, [AC_DEFINE(I_FLOATINGPOINT)]) +AC_CHECK_HEADER(libintl.h, [AC_DEFINE(I_LIBINTL)]) +AC_CHECK_HEADER(malloc.h, [AC_DEFINE(I_MALLOC)]) +AC_CHECK_HEADER(netdb.h, [AC_DEFINE(I_NETDB)]) +AC_CHECK_HEADER(netinet/in.h, [AC_DEFINE(I_NETINET_IN)]) +AC_CHECK_HEADER(netinet/tcp.h, [AC_DEFINE(I_NETINET_TCP)]) +AC_CHECK_HEADER(sys/errno.h, [AC_DEFINE(I_SYS_ERRNO)]) +AC_CHECK_HEADER(sys/file.h, [AC_DEFINE(I_SYS_FILE)]) +AC_CHECK_HEADER(sys/in.h, [AC_DEFINE(I_SYS_IN)]) +AC_CHECK_HEADER(sys/mman.h, [AC_DEFINE(I_SYS_MMAN)]) +AC_CHECK_HEADER(sys/page.h, [AC_DEFINE(I_SYS_PAGE)]) +AC_CHECK_HEADER(sys/param.h, [AC_DEFINE(I_SYS_PARAM)]) +AC_CHECK_HEADER(sys/socket.h, [AC_DEFINE(I_SYS_SOCKET)]) +AC_CHECK_HEADER(sys/stat.h, [AC_DEFINE(I_SYS_STAT)]) +AC_CHECK_HEADER(sys/types.h, [AC_DEFINE(I_SYS_TYPES)]) +AC_CHECK_HEADERS([sys/un.h ieeefp.h sys/resource.h sys/event.h sys/uio.h]) +AC_CHECK_HEADERS([poll.h sys/epoll.h sys/select.h sys/inotify.h fam.h]) +### C language support +# Only need to check C99 and GNU extensions + +AC_C_RESTRICT +AC_C_INLINE +AX_C___ATTRIBUTE__ + +if test "$ax_cv___attribute__" = "yes"; then + AX_GCC_MALLOC_CALL +fi + +### Types +# Again, no need to check for standard C89 types. + +AC_TYPE_SSIZE_T +AC_TYPE_PID_T +TYPE_SOCKLEN_T +AC_TYPE_UINT8_T +AC_TYPE_UINT16_T +AC_TYPE_INT32_T +AC_TYPE_UINT32_T +AC_TYPE_INT64_T +AC_TYPE_UINT64_T +AC_TYPE_INTMAX_T +AC_TYPE_UINTMAX_T + +AC_CHECK_SIZEOF([int]) +AC_CHECK_SIZEOF([long]) +AC_CHECK_SIZEOF([int64_t]) +AC_CHECK_SIZEOF([intmax_t]) +AC_CHECK_SIZEOF([time_t]) +AC_CHECK_SIZEOF([void *]) + +### Libraries +AC_CHECK_LIB(m, sin) +AC_CHECK_LIB(intl, gettext) +AC_CHECK_LIB(crypt, crypt) +LIB_SOCKET_NSL +AC_CHECK_LIB(fam, FAMOpen) + +# with_ssl=set +CHECK_SSL +if test "$HAVE_SSL" = "yes"; then + AC_DEFINE(HAVE_SSL) +fi + +# system libpcre +AX_PATH_LIB_PCRE() +if test "${PCRE_LIBS+set}" = "set"; then + AC_DEFINE(HAVE_PCRE) +fi + +### Databases + +AC_ARG_ENABLE(sql, AS_HELP_STRING([--disable-sql], +[Don't use SQL support]), enable_sql=$enableval, enable_sql=yes) + +if test "$enable_sql" = "yes"; then +AC_MSG_NOTICE([Looking for supported SQL servers]) +AX_LIB_MYSQL() +AX_LIB_POSTGRESQL() +AX_LIB_SQLITE3() +else +AC_MSG_NOTICE([Skipping SQL server checks]) +fi + +### Functions +AC_CHECK_FUNC(bindtextdomain, [AC_DEFINE(HAS_BINDTEXTDOMAIN)]) +AC_CHECK_FUNC(crypt, [AC_DEFINE(HAS_CRYPT)]) +AC_CHECK_FUNCS([fpsetmask fpsetround]) +AC_MSG_CHECKING([for isnormal]) +AC_LINK_IFELSE([ +#include +int main(void) { + return !isnormal(1.0); +} +], +[AC_MSG_RESULT(yes)] +[AC_DEFINE(HAVE_ISNORMAL)], +AC_MSG_RESULT(no)) + +AC_CHECK_FUNC(gai_strerror, [AC_DEFINE(HAS_GAI_STRERROR)]) +AC_CHECK_FUNC(getaddrinfo, [AC_DEFINE(HAS_GETADDRINFO)]) +AC_CHECK_FUNC(getdate, [AC_DEFINE(HAS_GETDATE)]) +AC_CHECK_FUNC(gethostbyname2, [AC_DEFINE(HAS_GETHOSTBYNAME2)]) +AC_CHECK_FUNC(getnameinfo, [AC_DEFINE(HAS_GETNAMEINFO)]) +AC_CHECK_FUNC(getpagesize, [AC_DEFINE(HAS_GETPAGESIZE)]) +AC_CHECK_FUNC(getrlimit, [AC_DEFINE(HAS_GETRLIMIT)]) +AC_CHECK_FUNC(getrusage, [AC_DEFINE(HAS_GETRUSAGE)]) +AC_CHECK_FUNCS([gettext getpid getppid]) +AC_CHECK_FUNC(inet_pton, [AC_DEFINE(HAS_INET_PTON)]) +AC_CHECK_FUNC(setitimer, [AC_DEFINE(HAS_ITIMER)]) +AC_CHECK_FUNC(setlocale, [AC_DEFINE(HAS_SETLOCALE)]) +AC_FUNC_FORK +AC_CHECK_FUNCS([setsid setpgid setpgrp]) +if test $ac_cv_func_setpgrp = yes; then +AC_FUNC_SETPGRP +fi +AC_CHECK_FUNCS([cbrt log2 round imaxdiv]) +AC_CHECK_FUNCS([getuid geteuid seteuid getpriority setpriority]) +AC_CHECK_FUNCS([socketpair sigaction sigprocmask valloc writev]) +AC_CHECK_FUNCS([fcntl pselect poll ppoll pollts kqueue epoll_ctl inotify_init]) +AC_CHECK_FUNCS([pread pwrite]) + +AC_FUNC_SNPRINTF +if test "x$ac_cv_have_working_snprintf" = xyes; then +AC_DEFINE(HAS_SNPRINTF) +fi +if test "x$ac_cv_have_working_vsnprintf" = xyes; then +AC_DEFINE(HAS_VSNPRINTF) +fi +AC_CHECK_FUNCS(_vsnprintf_s) + +AC_CHECK_FUNCS([strcasecmp strncasecmp _stricmp _strnicmp strdup]) +AC_FUNC_STRCOLL +AC_CHECK_FUNCS([strxfrm _strncoll _stricoll _strnicoll strdup]) +AC_CHECK_FUNC(sysconf, [AC_DEFINE(HAS_SYSCONF)]) +AC_CHECK_FUNC(textdomain, [AC_DEFINE(HAS_TEXTDOMAIN)]) + +AC_CHECK_FUNCS(waitpid) + +if test $ac_cv_func_waitpid = no; then + +AC_CHECK_FUNCS([wait3 wait]) +AC_MSG_CHECKING([for union wait]) +AC_CHECK_TYPES([union wait], [AC_DEFINE(UNION_WAIT) + AC_MSG_RESULT(yes)], AC_MSG_RESULT(no), + [AC_INCLUDES_DEFAULT + #ifdef I_SYS_WAIT + #include + #endif + ]) + +fi + + +### Variables, constants, defines and other misc. stuff + +AC_CHECK_DECLS(h_errno, [AC_DEFINE(HAVE_H_ERRNO)],,[AC_INCLUDES_DEFAULT +#ifdef I_NETDB +#include +#endif +]) + +AC_CHECK_TYPES([struct sockaddr_in6], [AC_DEFINE(HAVE_SOCKADDR_IN6)],, +[AC_INCLUDES_DEFAULT +#ifdef I_NETINET_IN +#include +#endif +]) + +# Will toupper()ing an already uppercase character be a problem? +AC_MSG_CHECKING([if it is safe to toupper uppers]) +AC_TRY_COMPILE( +[#include ], +[ +if (toupper('A') == 'A') + return 0; +else + return 1; +], ac_safe_toupper=yes, ac_safe_toupper=no) +AC_MSG_RESULT([$ac_safe_toupper]) +if test "x$ac_safe_toupper" = xyes; then + AC_DEFINE(HAVE_SAFE_TOUPPER) +fi + + + +# Which flavor of child killing to use? Prefer SIGCHLD. + +AC_CHECK_DECLS(SIGCHLD, [AC_DEFINE(HAVE_SIGCHLD)],,[AC_INCLUDES_DEFAULT +#include +]) + +AC_CHECK_DECLS(SIGCLD, [AC_DEFINE(HAVE_SIGCLD)],,[AC_INCLUDES_DEFAULT +#include +]) + + +### Files +AC_CHECK_FILE(/dev/urandom, [AC_DEFINE(HAS_DEV_URANDOM)]) + +### Misc features +AC_ARG_ENABLE(ipv6, AS_HELP_STRING([--disable-ipv6], + [Don't use IPv6 networking]), enable_ipv6=$enableval, enable_ipv6=yes) + +if test "$enable_ipv6" = "no"; then +AC_DEFINE(FORCE_IPV4) +fi + +AC_ARG_ENABLE(nls, AS_HELP_STRING([--disable-nls], + [Don't use message-translation]), enable_nls=$enableval, enable_nls=yes) + +if test "$enable_nls" = "no"; then +AC_DEFINE(DONT_TRANSLATE) +fi + +### Output + +AC_CONFIG_FILES([Makefile src/Makefile]) +AC_CONFIG_FILES([game/txt/compose.sh], [chmod +x game/txt/compose.sh]) +AC_CONFIG_FILES([test/alltests.sh], [chmod +x test/alltests.sh]) +AC_OUTPUT diff --git a/game/README b/game/README index 2251d7c..c4ce2cf 100644 --- a/game/README +++ b/game/README @@ -3,12 +3,12 @@ This document assumes that you've successfully compiled and installed PennMUSH as described in the main PennMUSH README file. -The next step is to create your configuration file. In the game directory -is a file called "mush.cnf". If you don't have mush.cnf, but you have -mushcnf.dst, you can copy mushcnf.dst to mush.cnf. This file is a list -of all runtime configuration options with their default settting. Change -them as you see fit. IMPORTANT: do not _delete_ any parameters. They -all need to be there. +The next step is to create your configuration file. In the game +directory is a file called "mush.cnf". If you don't have mush.cnf, but +you have mushcnf.dst, you can copy mushcnf.dst to mush.cnf. This file +is a list of all runtime configuration options with their default +settting. Change them as you see fit. IMPORTANT: do not _delete_ any +parameters. They all need to be there. WIN32: Under win32 using the Microsoft compiler, ignore the restart script. @@ -68,14 +68,15 @@ wrong. You should definitely shout a warning that building is not being saved. To attempt to fix the problem, do a @dbck to take care of any possible -minor weirdness in the database, then try doing a "@dump/paranoid", and -reading the checkpoint logfile (default is log/checkpt.log). This is -slow, but it will write out an uncorrupted database, and tell you what -it fixed. Back up that database and indb.Z, then figure out what you're -going to do next: you can take the game down with a kill -9, or attempt -to manually fix the problem by either @destroying the offending object, -or attempting to reset the attributes on the object that are causing a -problem. If "@dump/paranoid" dies, you are more or less out of luck. +minor weirdness in the database, then try doing a "@dump/paranoid", +and reading the checkpoint logfile (default is log/checkpt.log). This +is slow, but it will write out an uncorrupted database, and tell you +what it fixed. Back up that database and indb.Z, then figure out what +you're going to do next: you can take the game down with a kill -9, or +attempt to manually fix the problem by either @destroying the +offending object, or attempting to reset the attributes on the object +that are causing a problem. If "@dump/paranoid" dies, you are more or +less out of luck. The game may crash from time to time. It will generate a core file, usually; if you don't limit the coredumpsize or strip the executable, @@ -84,8 +85,8 @@ debugger. Javelin is interested in stack traces. You can do a stack trace in the following manner: Go into the directory where you keep your source code, and type netmud ../game/core -If you don't call your executable "netmud", substitute in whatever -you do call it. +If you don't call your executable "netmud", substitute in whatever you +do call it. You are looking for variables set to bizarre values - attempts to access objects that aren't there, attempts to use pointers which point @@ -102,26 +103,36 @@ trace. You can move through it using "up" and "down", and see exactly what the sequence of calls was. You can also use "print " to see the value of a variable at the time the game crashed. The "gdb" debugger is similar to "dbx"; with that, you can abbreviate -"print" as "p". - -Javelin appreciates news of any bugs found, and any patches that have -been written to deal with them. He is also interested in any extensions -that people make to the code, and requests that ones that are of more -than just local interest be sent to him for inclusion in the next -release of this code. - -One important thing to remember is, if the MUSH refuses to start, there -is probably a good reason. Check the MUSH log, and the core file, if -there is one. Make sure to back up your database before attempting to -restart -- remember that every time it restarts, it overwrites -indb.Z.old. If you restart three times and somehow manage to trash your -database each time (for example, a full process table zero'ing out your -files), you won't have a backup to restart from, unless you've backed -up your database before trying! +"print" as "p". It is the reccomended debugger to use; when gdb is +present on your system and you're using gcc as the compiler, gcc is +told to use a gdb-specific debugging format. + +If you want to start PennMUSH running under a debugger, instead of +attaching to an already-running process, it'll need two arguments: +--no-session, and the name of your config file if it is different than +mush.cnf. Without --no-session, the server will immediately fork off a +detatched child process, and the debugger will tell you that the +process exited normally.. + +The PennMUSH developers appreciate news of any bugs found, and any +patches that have been written to deal with them. We are also +interested in any extensions that people make to the code, and +requests that ones that are of more than just local interest be sent +to us for inclusion in the next release of this code. See +http://dev.pennmush.org. + +One important thing to remember is, if the MUSH refuses to start, +there is probably a good reason. Check the MUSH log, and the core +file, if there is one. Make sure to back up your database before +attempting to restart -- remember that every time it restarts, it +overwrites indb.Z.old. If you restart three times and somehow manage +to trash your database each time (for example, a full process table +zero'ing out your files), you won't have a backup to restart from, +unless you've backed up your database before trying! You can also find helpful tips in Javelin's Guide for Gods, which is available on the WWW as - http://pennmush.org/~alansz/guide.html -and by ftp from pennmush.org as - /pub/DuneMUSH/Guide/guide-single.txt + http://javelin.pennmush.org/~alansz/guide.html +and by ftp from ftp.pennmush.org as + /PennMUSH/Guide/guide-single.txt diff --git a/game/data/README b/game/data/README deleted file mode 100644 index 42f363b..0000000 --- a/game/data/README +++ /dev/null @@ -1 +0,0 @@ -Database files are usually kept here. diff --git a/game/log/README b/game/log/README index 8b13789..a1506f7 100644 --- a/game/log/README +++ b/game/log/README @@ -1 +1,22 @@ + +What they're used for: + +checkpt.log: + Database saves are recorded here. + +command.log: + Logging of SUSPECT player activity and other command logging. + +connect.log: + All connections and disconnections are recorded here. + +netmush.log: + General server messages and errors. + +trace.log: + Memory allocation stats and errors are recorded here. + +wizard.log: + Logs of game-altering things done by wizards, and things done TO + them. diff --git a/game/mushcnf.dst b/game/mushcnf.dst index 509146d..c806c67 100644 --- a/game/mushcnf.dst +++ b/game/mushcnf.dst @@ -226,7 +226,7 @@ idle_time 30m # mushes use. This option will make the server automatically send a # TCP-level 'Are you still there?' query every few minutes to keep the # connection active. -# NOTE: This doesn't work on all OSes, but does some of the most popular +# NOTE: This doesn't work on all OSes, but does on the most popular # ones for mush hosting such as linux. Other options include the KEEPALIVE # flag and the IDLE command. keepalive_timeout 5m @@ -573,15 +573,17 @@ room_connects no ### # What SQL server platform should we use? Options include: -# mysql, disabled (the default) +# mysql, postgresql, sqlite3, disabled (the default) sql_platform disabled # What's the SQL hostname? Use '127.0.0.1' for a TCP connection -# to the local host, and 'localhost' for a domain socket connection. +# to the local host on port 3306, ':' for a TCP +# connection on another port (e.g. 127.0.0.1:3307), and +# the word 'localhost' for a domain socket connection. sql_host 127.0.0.1 # What's the SQL database? You have to set this to a database that -# you create. +# you create, or the filename of a sqlite3 database. sql_database mush # What username to access the database? @@ -608,6 +610,9 @@ function_side_effects yes # default whisper to whisper/noisy instead of whisper/silent noisy_whisper no +# default @cemit to @cemit/noisy instead of @cemit/silent +noisy_cemit no + # is possessive get (get players's object) allowed? possessive_get yes diff --git a/game/txt/Makefile b/game/txt/Makefile index 6ec3e5a..10b7d08 100644 --- a/game/txt/Makefile +++ b/game/txt/Makefile @@ -46,6 +46,4 @@ clean: -rm -f compose.sh -rm -f hlp/*.orig hlp/*.rej hlp/\#* hlp/*~ -compose.sh: compose.sh.SH - sh compose.sh.SH diff --git a/game/txt/changes/0.80 b/game/txt/changes/0.80 index 7b60e63..a5659f1 100644 --- a/game/txt/changes/0.80 +++ b/game/txt/changes/0.80 @@ -5,10 +5,12 @@ CobraMUSH Version 0.80 (See 'changes entries' for a list of all versions.) Major Changes: - * Implmented CobraMUSH modules - * All *local.c files moved over to module hooks. + * Implemented CobraMUSH modules. [RLB] + * All *local.c files moved over to module hooks. [RLB] + * Embedded the lua scripting engine. [RLB] Minor Changes: - * LUA Scripting Engine Embedding. + * Mortal switch removed from @uptime [RLB] + * Removed incomplete and unused SWMP system Fixes: * All fixes from pre-0.80 development series. diff --git a/game/txt/compose.sh.SH b/game/txt/compose.sh.SH index 31c8453..e69de29 100644 --- a/game/txt/compose.sh.SH +++ b/game/txt/compose.sh.SH @@ -1,82 +0,0 @@ -#!/bin/sh -case $CONFIG in -'') - if test -f config.sh; then TOP=.; - elif test -f ../config.sh; then TOP=..; - elif test -f ../../config.sh; then TOP=../..; - elif test -f ../../../config.sh; then TOP=../../..; - elif test -f ../../../../config.sh; then TOP=../../../..; - else - echo "Can't find config.sh."; exit 1 - fi - . $TOP/config.sh - ;; -esac -: This forces SH files to create target in same directory as SH file. -: This is so that make depend always knows where to find SH derivatives. -case "$0" in -*/*) cd `expr X$0 : 'X\(.*\)/'` ;; -esac -echo "Extracting compose.sh (with variable substitutions)" -: This section of the file will have variable substitutions done on it. -: Move anything that needs config subs from !NO!SUBS! section to !GROK!THIS!. -: Protect any dollar signs and backticks that you do not want interpreted -: by putting a backslash in front. You may delete these comments. -$spitshell >compose.sh < -# Example: compose.sh help -# -# This script calls index-files.pl -# -# By Alan Schwartz (Javelin/Paul) -# - -# These come from Configure -perl=${perl-none} -test=$test -cat=$cat -rm=$rm -echo=$echo - -!GROK!THIS! - -: In the following dollars and backticks do not need the extra backslash. -$spitshell >>compose.sh <<'!NO!SUBS!' -# This process can eat CPU, so uncomment if you want to be nice -#/etc/renice +4 $$ - -# What subdirectories should we be processing? -dir=$1 -if $test ! -d $dir; then - $echo "Usage: compose.sh " - exit 0 -fi - -index_args=$2 - -# Ok, let's do 'em: - cd $dir - - # Remove the old index - $rm -f index.$dir - - # Build a new index, and tack it on. - $echo Building index for $dir... - if test -f $perl; then - $cat *.$dir | tee ../$dir.txt | $perl ../index-files.pl $index_args > index.$dir - $cat index.$dir >> ../$dir.txt - else - $cat *.$dir > ../$dir.txt - fi - - cd .. - -$echo Done. -$echo Remember to use @readcache if the mush is currently running. -!NO!SUBS! -chmod 755 compose.sh -$eunicefix compose.sh diff --git a/game/txt/hlp/cobra_chat.hlp b/game/txt/hlp/cobra_chat.hlp index c1f7698..5d655cc 100644 --- a/game/txt/hlp/cobra_chat.hlp +++ b/game/txt/hlp/cobra_chat.hlp @@ -3,18 +3,18 @@ CHAT SYSTEM The MUSH has a built-in chat system with many different channels. - These channels vary from MUSH to MUSH; ask at your local site or - use @channel/list to see which ones are available. + These channels vary from MUSH to MUSH; ask at your local site or use + @channel/list to see which ones are available. You can talk to many people on the MUSH via the chat system, without needing to be in the same room as them. Use the "@channel" command - to join, leave, or check who is on a channel, and use the "@chat" - or "+" command to communicate. + to join, leave, or check who is on a channel, and use the "@chat" or + "+" command to communicate. - If you examine yourself, you will see a list of channels that you are - currently listening to. Some channels are restricted to wizards or - administrators only. See the following help topics for details: - @chat, @channel, @cemit, @clock, cwho() + If you examine yourself, you will see a list of channels that you + are currently listening to. Some channels are restricted to wizards + or administrators only. See the following help topics for details: + @chat, @channel, @cemit, @clock, cwho() & + & @chat @@ -59,10 +59,10 @@ See also: chat a player name as a second argument. Channels may be restricted in who can join them and/or speak on - them. @channel/list will show you the channel's name, number of users, - number of message since last restart, access information, and your - status. See "help channel-list" for an explanation of how to read - the listing. + them. @channel/list will show you the channel's name, number of + users, number of message since last restart, access information, and + your status. See "help channel-list" for an explanation of how to + read the listing. @channel/what will show you the channel's name, access information, and a description of the channel's purpose. @@ -73,43 +73,48 @@ See also: chat & @channel2 @channel/who @channel/hide = - @channel/title = + @channel/title [=] - The @channel/who command shows you who is currently on a channel, - if you are permitted to see it. + The @channel/who command shows you who is currently on a channel, if + you are permitted to see it. Some channels allow their users to hide from the @channel/who list. - If you're on such a channel and are permitted to hide, you can - use @channel/hide =yes to hide yourself, and - @channel/hide =no to reappear. + If you're on such a channel and are permitted to hide, you can use + @channel/hide =yes to hide yourself, and @channel/hide + =no to reappear. - @channel/title lets you set a title to appear before your name - when you speak on the channel. If you leave the channel, your - title is cleared; use @channel/gag instead (see help @channel3). + @channel/title lets you set a title to appear before your name when + you speak on the channel, or check your current title. If you leave + the channel, your title is cleared; use @channel/gag instead (see + help @channel3). You should escape any commas in your title with + backslashes. See "help @channel3" for more. & @channel3 @channel/mute = @channel/gag = - @channel/recall [ = [,] ] - - Some channels broadcast messages when players connect or disconnect from - the MUSH. If you don't want to hear those messages, use @channel/mute - =yes. To resume hearing the messages, use @channel/mute - =no or @channel/unmute . Leave out - to mute or unmute all channels. - - If you want to remain on a channel but not receive any messages - on the channel, use @channel/gag =yes. To resume hearing, - use @channel/gag =no (or @channel/ungag ). When - you disconnect, the channel will be automatically ungagged for you. - Leave out to gag or ungag all channels. If the channel does - not have the "open" priv, you can not speak on it while you are gagged. + @channel/recall [ = [,] ] + + Some channels broadcast messages when players connect or disconnect + from the MUSH. If you don't want to hear those messages, use + @channel/mute =yes. To resume hearing the messages, use + @channel/mute =no or @channel/unmute . Leave out + to mute or unmute all channels. + + If you want to remain on a channel but not receive any messages on + the channel, use @channel/gag =yes. To resume hearing, use + @channel/gag =no (or @channel/ungag ). When you + disconnect, the channel will be automatically ungagged for you. + Leave out to gag or ungag all channels. If the channel + does not have the "open" priv, you can not speak on it while you are + gagged. @channel/recall shows you the most recent messages on the channel; the number of messages depends on how the channel is configured, but - can be limited by specifying to show and a to start - display from. You must be on a channel to recall from it. + can be limited by specifying to show and a to + start display from. If is an elapsed time, like '1h', + messages from within the given interval will be recalled. You must + be on a channel or able to join it to recall from it. See "help @channel4" for more. & @channel4 @@ -193,9 +198,9 @@ Size of the channel buffer in full-length lines---------------------------/ @clock/mod [= ] The @clock command modifies the a lock on a chat channel if the - extended chat system is in use. If no key is specified, the - lock is unlocked. Evaluation locks will not work with @clock. - See help @clock2 for information on using indirect locks. + extended chat system is in use. If no key is specified, the lock is + unlocked. Evaluation locks will not work with @clock. See help + @clock2 for information on using indirect locks. The "join" lock restricts who can join the channel. The "speak" lock restricts who can speak to the channel. @@ -204,16 +209,16 @@ Size of the channel buffer in full-length lines---------------------------/ The "mod" lock restricts who can modify the channel. If you pass the mod lock on the channel, you can do anything short of deleting it. - When new channels are added, the mod lock is set to the creator/owner, - and all other locks are unlocked. + When new channels are added, the mod lock is set to the + creator/owner, and all other locks are unlocked. See help @clock2 for how to use indirect locks to lock a channel to anything. & @clock2 -If user-defined locks are available, you can use indirect @clocks -to lock a channel to a lock of any type (including evaluation locks) -on a VISUAL object. This channel can only be joined by an UNFINDABLE player: +You can use indirect @clocks to lock a channel to a lock of any type +(including evaluation locks) on a VISUAL object. This channel can only +be joined by an UNFINDABLE player: >@clock/join unfindchannel=@#10 >@lock/user:ChanJoinLock #10=isunfind/1 @@ -241,15 +246,15 @@ specific indirect lock instead of the default one: & CTITLE() ctitle(,) - Returns 's @chan/title on . You must either - be able to examine the object, or it must visible be on a channel - which you are allowed to join. + Returns 's @chan/title on . You must either be able + to examine the object, or it must be visibly on a channel which you + are allowed to join. & CSTATUS() cstatus(,) Returns 's status with respect to , which may be - "Off", "On", or "Gag". You must either be able to examine the object, - or it must visible be on the channel; "Off" is returned for + "Off", "On", or "Gag". You must either be able to examine the + object, or it must visible be on the channel; "Off" is returned for objects that you can not see on the channel. & CDESC() & CUSERS() @@ -260,9 +265,17 @@ specific indirect lock instead of the default one: cmsgs() cbuffer() - Return the description, number of users, number of messages, - or buffer size of , respectively. This information is - also displayed in @chan/list. + Return the description, number of users, number of messages, or + buffer size of , respectively. This information is also + displayed in @chan/list. +& CBUFFERADD() + cbufferadd(, [, ]) + + Adds text to a chan buffer without broadcasting it to all people on + the channel. If is true, it will spoof the encator (%#), + and you must be able to perform an @nscemit. + + This function is only usable by objects that pass the channel's @clock/mod. & CWHO() cwho() @@ -283,18 +296,16 @@ specific indirect lock instead of the default one: clflags() clflags(,) - With one argument, cflags() returns a list of flags set on the - given channel, represented as a string of characters. See - 'help channel-list' for the list of flags (they appear in the - "Access" column). You must be able to see the channel to use this - function. + With one argument, cflags() returns a list of flags set on the given + channel, represented as a string of characters. See 'help + channel-list' for the list of flags (they appear in the "Access" + column). You must be able to see the channel to use this function. - With two arguments, cflags() returns a list of flags for that - object on that channel, currently a string consisting of zero - or more of "G" (gagging), "Q" (muted), and "H" (hidden). - You must be able to see that channel and to examine the object - to use this function. If the object is not on the channel, an - error is returned. + With two arguments, cflags() returns a list of flags for that object + on that channel, currently a string consisting of zero or more of + "G" (gagging), "Q" (muted), and "H" (hidden). You must be able to + see that channel and to examine the object to use this function. If + the object is not on the channel, an error is returned. The clflags versions return a space-separated list of flag names, rather than a string of flag characters. @@ -304,26 +315,25 @@ specific indirect lock instead of the default one: channels([,]) With no arguments, channels() returns the list of all channel names - which are visible to the player. With two arguments, returns the list - of channel names to which the object is listening, delimited by + which are visible to the player. With two arguments, returns the + list of channel names to which the object is listening, delimited by . With one argument, the behavior is ambiguous. If the argument - matches an object, returns the list of names to which the object - is listening, space-delimited. If not, it's treated as a no-argument + matches an object, returns the list of names to which the object is + listening, space-delimited. If not, it's treated as a no-argument case with a delimiter. - If you don't have permission to examine the object, you only see - those channels to which the object belong for which you have + If you don't have permission to examine the object, you only see + those channels to which the object belong for which you have permission to join (or are joined to). & CLOCK() clock([/][, ]) With one argument, returns the value of a lock on a channel, if you - own the channel or are See_All. If no locktype is given, "JOIN" - is assumed. - With two arguments, sets the lock if you would be able to do so via - @clock. + own the channel or are See_All. If no locktype is given, "JOIN" is + assumed. With two arguments, sets the lock if you would be able to + do so via @clock. See also: @clock & CRECALL() diff --git a/game/txt/hlp/cobra_conf.hlp b/game/txt/hlp/cobra_conf.hlp index b0ad370..0eec5ec 100644 --- a/game/txt/hlp/cobra_conf.hlp +++ b/game/txt/hlp/cobra_conf.hlp @@ -29,6 +29,8 @@ max_channels=: How many channels can exist total. max_player_channels=>number>: How many channels can each non-admin player create? If 0, mortals cannot create channels. + noisy_cemit=: Is @cemit/noisy the default? + & @config cmds These options affect command behavior. diff --git a/hdrs/access.h b/hdrs/access.h index 051fd56..1409c7e 100644 --- a/hdrs/access.h +++ b/hdrs/access.h @@ -6,29 +6,30 @@ * It's organized into a linked list of access rules. */ struct access { - char host[BUFFER_LEN]; /**< The host pattern */ - char comment[BUFFER_LEN]; /**< A comment about the rule */ + char *host; /**< The host pattern */ + char *comment; /**< A comment about the rule */ dbref who; /**< Who created this rule if sitelock used */ - int can; /**< Bitflags of what the host can do */ - int cant; /**< Bitflags of what the host can't do */ + uint32_t can; /**< Bitflags of what the host can do */ + uint32_t cant; /**< Bitflags of what the host can't do */ + pcre *re; /**< Compiled regexp */ struct access *next; /**< Pointer to next rule in the list */ }; /* These flags are can/can't - a site may or may not be allowed to do them */ -#define ACS_CONNECT 0x1 /* Connect to non-guests */ -#define ACS_CREATE 0x2 /* Create new players */ -#define ACS_GUEST 0x4 /* Connect to guests */ -#define ACS_REGISTER 0x8 /* Site can use the 'register' command */ +#define ACS_CONNECT 0x1U /* Connect to non-guests */ +#define ACS_CREATE 0x2U /* Create new players */ +#define ACS_GUEST 0x4U /* Connect to guests */ +#define ACS_REGISTER 0x8U /* Site can use the 'register' command */ /* These flags are set in the 'can' bit, but they mark special processing */ -#define ACS_SITELOCK 0x10 /* Marker for where to insert @sitelock */ -#define ACS_SUSPECT 0x20 /* All players from this site get SUSPECT */ -#define ACS_DENY_SILENT 0x40 /* Don't log failed attempts */ -#define ACS_REGEXP 0x80 /* Treat the host pattern as a regexp */ +#define ACS_SITELOCK 0x10U /* Marker for where to insert @sitelock */ +#define ACS_SUSPECT 0x20U /* All players from this site get SUSPECT */ +#define ACS_DENY_SILENT 0x40U /* Don't log failed attempts */ +#define ACS_REGEXP 0x80U /* Treat the host pattern as a regexp */ -#define ACS_GOD 0x100 /* God can connect from this site */ -#define ACS_DIRECTOR 0x200 /* Directors can connect from this site */ -#define ACS_ADMIN 0x400 /* Admins can connect from this site */ +#define ACS_GOD 0x100U /* God can connect from this site */ +#define ACS_DIRECTOR 0x200U /* Directors can connect from this site */ +#define ACS_ADMIN 0x400U /* Admins can connect from this site */ /* This is the usual default access */ #define ACS_DEFAULT (ACS_CONNECT|ACS_CREATE|ACS_GUEST) @@ -44,18 +45,18 @@ struct access { #define Forbidden_Site(hname) (!site_can_access(hname,ACS_DEFAULT, AMBIGUOUS)) /* Public functions */ -int read_access_file(void); +bool read_access_file(void); void write_access_file(void); -int site_can_access(const char *hname, int flag, dbref who); +bool site_can_access(const char *hname, uint32_t flag, dbref who); struct access *site_check_access(const char *hname, dbref who, int *rulenum); -int format_access(struct access *ap, int rulenum, - dbref who - __attribute__ ((__unused__)), char *buff, char **bp); -int add_access_sitelock(dbref player, const char *host, dbref who, int can, - int cant); +void format_access(struct access *ap, int rulenum, + dbref who + __attribute__ ((__unused__)), char *buff, char **bp); +bool add_access_sitelock(dbref player, const char *host, dbref who, + uint32_t can, uint32_t cant); int remove_access_sitelock(const char *pattern); void do_list_access(dbref player); int parse_access_options - (const char *opts, dbref *who, int *can, int *cant, dbref player); + (const char *opts, dbref *who, uint32_t * can, uint32_t * cant, dbref player); #endif /* __ACCESS_H */ diff --git a/hdrs/ansi.h b/hdrs/ansi.h index b09b297..8034fc8 100644 --- a/hdrs/ansi.h +++ b/hdrs/ansi.h @@ -16,54 +16,172 @@ #ifndef __ANSI_H #define __ANSI_H -#define ANSI_BLACK_V (30) -#define ANSI_RED_V (31) -#define ANSI_GREEN_V (32) -#define ANSI_YELLOW_V (33) -#define ANSI_BLUE_V (34) -#define ANSI_MAGENTA_V (35) -#define ANSI_CYAN_V (36) -#define ANSI_WHITE_V (37) +#include "mushtype.h" +#include "mypcre.h" #define BEEP_CHAR '\a' #define ESC_CHAR '\x1B' -#define ANSI_BEGIN "\x1B[" +#define ANSI_RAW_NORMAL "\x1B[0m" -#define ANSI_NORMAL "\x1B[0m" +#define TAG_START '\002' +#define TAG_END '\003' +#define MARKUP_START "\002" +#define MARKUP_END "\003" -#define ANSI_HILITE "\x1B[1m" -#define ANSI_INVERSE "\x1B[7m" -#define ANSI_BLINK "\x1B[5m" -#define ANSI_UNDERSCORE "\x1B[4m" +#define ANSI_HILITE MARKUP_START "ch" MARKUP_END +#define ANSI_INVERSE MARKUP_START "ci" MARKUP_END +#define ANSI_BLINK MARKUP_START "cf" MARKUP_END +#define ANSI_UNDERSCORE MARKUP_START "cu" MARKUP_END -#define ANSI_INV_BLINK "\x1B[7;5m" -#define ANSI_INV_HILITE "\x1B[1;7m" -#define ANSI_BLINK_HILITE "\x1B[1;5m" -#define ANSI_INV_BLINK_HILITE "\x1B[1;5;7m" +#define ANSI_INV_BLINK MARKUP_START "cfi" MARKUP_END +#define ANSI_INV_HILITE MARKUP_START "chi" MARKUP_END +#define ANSI_BLINK_HILITE MARKUP_START "cfh" MARKUP_END +#define ANSI_INV_BLINK_HILITE MARKUP_START "cifh" MARKUP_END /* Foreground colors */ -#define ANSI_BLACK "\x1B[30m" -#define ANSI_RED "\x1B[31m" -#define ANSI_GREEN "\x1B[32m" -#define ANSI_YELLOW "\x1B[33m" -#define ANSI_BLUE "\x1B[34m" -#define ANSI_MAGENTA "\x1B[35m" -#define ANSI_CYAN "\x1B[36m" -#define ANSI_WHITE "\x1B[37m" +#define ANSI_PLAIN MARKUP_START "n" MARKUP_END +#define ANSI_BLACK MARKUP_START "cx" MARKUP_END +#define ANSI_RED MARKUP_START "cr" MARKUP_END +#define ANSI_GREEN MARKUP_START "cg" MARKUP_END +#define ANSI_YELLOW MARKUP_START "cy" MARKUP_END +#define ANSI_BLUE MARKUP_START "cb" MARKUP_END +#define ANSI_MAGENTA MARKUP_START "cm" MARKUP_END +#define ANSI_CYAN MARKUP_START "cc" MARKUP_END +#define ANSI_WHITE MARKUP_START "cw" MARKUP_END + +#define ANSI_HIBLACK MARKUP_START "chx" MARKUP_END +#define ANSI_HIRED MARKUP_START "chr" MARKUP_END +#define ANSI_HIGREEN MARKUP_START "chg" MARKUP_END +#define ANSI_HIYELLOW MARKUP_START "chy" MARKUP_END +#define ANSI_HIBLUE MARKUP_START "chb" MARKUP_END +#define ANSI_HIMAGENTA MARKUP_START "chm" MARKUP_END +#define ANSI_HICYAN MARKUP_START "chc" MARKUP_END +#define ANSI_HIWHITE MARKUP_START "chw" MARKUP_END /* Background colors */ -#define ANSI_BBLACK "\x1B[40m" -#define ANSI_BRED "\x1B[41m" -#define ANSI_BGREEN "\x1B[42m" -#define ANSI_BYELLOW "\x1B[43m" -#define ANSI_BBLUE "\x1B[44m" -#define ANSI_BMAGENTA "\x1B[45m" -#define ANSI_BCYAN "\x1B[46m" -#define ANSI_BWHITE "\x1B[47m" +#define ANSI_BBLACK MARKUP_START "cX" MARKUP_END +#define ANSI_BRED MARKUP_START "cR" MARKUP_END +#define ANSI_BGREEN MARKUP_START "cG" MARKUP_END +#define ANSI_BYELLOW MARKUP_START "cY" MARKUP_END +#define ANSI_BBLUE MARKUP_START "cB" MARKUP_END +#define ANSI_BMAGENTA MARKUP_START "cM" MARKUP_END +#define ANSI_BCYAN MARKUP_START "cC" MARKUP_END +#define ANSI_BWHITE MARKUP_START "cW" MARKUP_END + +#define ANSI_END MARKUP_START "c/" MARKUP_END +#define ANSI_ENDALL MARKUP_START "c/a" MARKUP_END + +#define ANSI_NORMAL ANSI_ENDALL + +void init_ansi_codes(void); + +#ifdef HAVE_STDINT_H +#include +#endif + +typedef struct _ansi_data { + uint8_t bits; + uint8_t offbits; + char fore; + char back; +} ansi_data; + +int read_raw_ansi_data(ansi_data *store, const char *codes); +int write_raw_ansi_data(ansi_data *old, ansi_data *cur, char *buff, char **bp); + +void define_ansi_data(ansi_data *store, const char *str); +int write_ansi_data(ansi_data *cur, char *buff, char **bp); + + +void nest_ansi_data(ansi_data *old, ansi_data *cur); + +#define MARKUP_COLOR 'c' +#define MARKUP_COLOR_STR "c" +#define MARKUP_COLOR_OLD 'a' +#define MARKUP_HTML 'p' +#define MARKUP_HTML_STR "p" + +/* Markup information necessary for ansi_string */ + +/* Miscellaneous notes on markup_information: + * If "start" is negative, there are two cases: + * end >= 0 :: A stand-alone tag, starting at "end". + * end < 0 :: A tag set for removal. + * If start is non-negative while end is negative, something's broken. + * + * Markup surrounding a character ends to the right of that character: + * In the string "abc", if 'b' has a markup assigned to only itself, + * start = 1, end = 2. (Instead of end = 1) + */ + +typedef struct _markup_information { + char *start_code; + char *stop_code; + char type; + int start; + int end; + int priority; +} markup_information; + +/** A string, with ansi attributes broken out from the text */ +typedef struct _ansi_string { + char text[BUFFER_LEN]; /**< Text of the string */ + ansi_data ansi[BUFFER_LEN]; /**< ANSI of the string */ + markup_information markup[BUFFER_LEN]; /**< The markup_information list */ + int nmarkups; /**< Number of Pueblo markups */ + int len; /**< Length of text */ + int optimized; /**< Has this ansi_string been optimized? */ +} ansi_string; + +int ansi_strcmp(const char *astr, const char *bstr); +extern char *remove_markup(const char *orig, size_t * stripped_len); +extern char *skip_leading_ansi(const char *p); + +extern ansi_string * +parse_ansi_string(const char *src) + __attribute_malloc__; + extern void flip_ansi_string(ansi_string *as); + extern void free_ansi_string(ansi_string *as); + +/* Append X characters to the end of a string, taking ansi and html codes into + account. */ + extern int safe_ansi_string(ansi_string *as, int start, int len, + char *buff, char **bp); + +/* Modifying ansi strings */ + ansi_string *real_parse_ansi_string(const char *src) + __attribute_malloc__; + int ansi_string_delete(ansi_string *as, int start, int count); + int ansi_string_insert(ansi_string *dst, int loc, ansi_string *src); + int ansi_string_replace(ansi_string *dst, int loc, int size, + ansi_string *src); + ansi_string *scramble_ansi_string(ansi_string *as); + void optimize_ansi_string(ansi_string *as); + +/* Dump the penn code required to recreate the ansi_string */ + extern int dump_ansi_string(ansi_string *as, char *buff, char **bp); + + int ansi_pcre_copy_substring(ansi_string *as, int *ovector, int stringcount, + int stringnumber, int nonempty, char *buffer, + char **bp); + + int ansi_pcre_copy_named_substring(const pcre * code, ansi_string *as, + int *ovector, int stringcount, + const char *stringname, int nonempty, + char *buffer, char **bp); -#define ANSI_END "m" +/* Pueblo stuff */ +#define open_tag(x) tprintf("%c%c%s%c",TAG_START,MARKUP_HTML,x,TAG_END) +#define close_tag(x) tprintf("%c%c/%s%c",TAG_START,MARKUP_HTML,x,TAG_END) +#define wrap_tag(x,y) tprintf("%c%c%s%c%s%c%c/%s%c", \ + TAG_START,MARKUP_HTML,x,TAG_END, \ + y, TAG_START,MARKUP_HTML,x,TAG_END) + int safe_tag(char const *a_tag, char *buf, char **bp); + int safe_tag_cancel(char const *a_tag, char *buf, char **bp); + int safe_tag_wrap(char const *a_tag, char const *params, + char const *data, char *buf, char **bp, dbref player); #endif /* __ANSI_H */ diff --git a/hdrs/atr_tab.h b/hdrs/atr_tab.h index d32c0d4..85764e2 100644 --- a/hdrs/atr_tab.h +++ b/hdrs/atr_tab.h @@ -69,10 +69,10 @@ ATTR attr[] = { {"FILTER", AF_NOPROG | AF_PREFIXMATCH, NULL_CHUNK_REFERENCE, 0, TRUE_BOOLEXP, TRUE_BOOLEXP, 0, NULL}, {"FOLLOW", AF_NOPROG | AF_PREFIXMATCH, NULL_CHUNK_REFERENCE, 0, TRUE_BOOLEXP, TRUE_BOOLEXP, 0, NULL}, - {"FOLLOWING", AF_NOPROG | AF_PRIVATE | AF_PRIVILEGE | AF_NOCOPY, - NULL_CHUNK_REFERENCE, 0 | AF_PREFIXMATCH, TRUE_BOOLEXP, TRUE_BOOLEXP, 0, NULL}, - {"FOLLOWERS", AF_NOPROG | AF_PRIVATE | AF_PRIVILEGE | AF_NOCOPY, - NULL_CHUNK_REFERENCE, 0 | AF_PREFIXMATCH, TRUE_BOOLEXP, TRUE_BOOLEXP, 0, NULL}, + {"FOLLOWING", AF_NOPROG | AF_PRIVATE | AF_PRIVILEGE | AF_NOCOPY | AF_PREFIXMATCH, + NULL_CHUNK_REFERENCE, 0, TRUE_BOOLEXP, TRUE_BOOLEXP, 0, NULL}, + {"FOLLOWERS", AF_NOPROG | AF_PRIVATE | AF_PRIVILEGE | AF_NOCOPY | AF_PREFIXMATCH, + NULL_CHUNK_REFERENCE, 0 , TRUE_BOOLEXP, TRUE_BOOLEXP, 0, NULL}, {"FORWARDLIST", AF_NOPROG | AF_PRIVATE | AF_PREFIXMATCH, NULL_CHUNK_REFERENCE, 0, TRUE_BOOLEXP, TRUE_BOOLEXP, 0, NULL}, {"GIVE", AF_NOPROG | AF_PREFIXMATCH, NULL_CHUNK_REFERENCE, 0, TRUE_BOOLEXP, TRUE_BOOLEXP, 0, NULL}, @@ -144,6 +144,7 @@ ATTR attr[] = { {"OZENTER", AF_NOPROG | AF_PREFIXMATCH, NULL_CHUNK_REFERENCE, 0, TRUE_BOOLEXP, TRUE_BOOLEXP, 0, NULL}, {"OZLEAVE", AF_NOPROG | AF_PREFIXMATCH, NULL_CHUNK_REFERENCE, 0, TRUE_BOOLEXP, TRUE_BOOLEXP, 0, NULL}, {"PAYMENT", AF_NOPROG | AF_PREFIXMATCH, NULL_CHUNK_REFERENCE, 0, TRUE_BOOLEXP, TRUE_BOOLEXP, 0, NULL}, + /* TODO: Add @pageformat.. This snuck in a long time ago into PennMUSH, nifty feature we should add */ {"PRICELIST", AF_NOPROG | AF_PREFIXMATCH, NULL_CHUNK_REFERENCE, 0, TRUE_BOOLEXP, TRUE_BOOLEXP, 0, NULL}, {"PREFIX", AF_NOPROG | AF_PREFIXMATCH, NULL_CHUNK_REFERENCE, 0, TRUE_BOOLEXP, TRUE_BOOLEXP, 0, NULL}, {"RECEIVE", AF_NOPROG | AF_PREFIXMATCH, NULL_CHUNK_REFERENCE, 0, TRUE_BOOLEXP, TRUE_BOOLEXP, 0, NULL}, diff --git a/hdrs/attrib.h b/hdrs/attrib.h index c3234f4..26b90d5 100644 --- a/hdrs/attrib.h +++ b/hdrs/attrib.h @@ -92,10 +92,10 @@ extern int do_set_atr(dbref thing, char const *RESTRICT atr, char const *RESTRICT s, dbref player, unsigned int flags); extern void do_atrlock(dbref player, char const *arg1, char const *arg2, char write_lock); extern void do_atrchown(dbref player, char const *arg1, char const *arg2); -extern int string_to_atrflag(dbref player, const char *p); -extern int string_to_atrflagsets(dbref player, const char *p, int *setbits, - int *clrbits); -extern const char *atrflag_to_string(int mask); +extern int string_to_atrflag(dbref player, char const *p, privbits *bits); +extern int string_to_atrflagsets(dbref player, const char *p, privbits *setbits, + privbits *clrbits); +extern const char *atrflag_to_string(privbits mask); extern void init_atr_name_tree(void); extern int can_read_attr_internal(dbref player, dbref obj, ATTR *attr); diff --git a/hdrs/bufferq.h b/hdrs/bufferq.h index ef77331..1133751 100644 --- a/hdrs/bufferq.h +++ b/hdrs/bufferq.h @@ -1,5 +1,3 @@ -#ifndef _BUFFERQ_H_ -#define _BUFFERQ_H_ /** * \file bufferq.h * @@ -9,7 +7,8 @@ */ -#define BUFFERQLINEOVERHEAD (2*sizeof(int)+sizeof(time_t)+sizeof(dbref)) +#ifndef BUFFERQ_H +#define BUFFERQ_H typedef struct bufferq BUFFERQ; @@ -27,13 +26,14 @@ struct bufferq { #define BufferQLast(b) ((b)->last_string) #define BufferQLastType(b) ((b)->last_type) -extern BUFFERQ *allocate_bufferq(int lines); -extern BUFFERQ *reallocate_bufferq(BUFFERQ * bq, int lines); -extern void free_bufferq(BUFFERQ * bq); -extern void add_to_bufferq(BUFFERQ * bq, int type, dbref player, - const char *msg); -extern char *iter_bufferq(BUFFERQ * bq, char **p, dbref *player, int *type, - time_t * timestamp); -extern int bufferq_lines(BUFFERQ * bq); -extern int isempty_bufferq(BUFFERQ * bq); +BUFFERQ *allocate_bufferq(int lines); +BUFFERQ *reallocate_bufferq(BUFFERQ *bq, int lines); +void free_bufferq(BUFFERQ *bq); +void add_to_bufferq(BUFFERQ *bq, int type, dbref player, const char *msg); +char *iter_bufferq(BUFFERQ *bq, char **p, dbref *player, int *type, + time_t * timestamp); +int bufferq_lines(BUFFERQ *bq); +int bufferq_blocks(BUFFERQ *bq); +bool isempty_bufferq(BUFFERQ *bq); + #endif diff --git a/hdrs/case.h b/hdrs/case.h index ae1912d..aa3e150 100644 --- a/hdrs/case.h +++ b/hdrs/case.h @@ -3,7 +3,7 @@ #include #include "config.h" -#ifdef HAS_SAFE_TOUPPER +#ifdef HAVE_SAFE_TOUPPER #define DOWNCASE(x) tolower((unsigned char)x) #define UPCASE(x) toupper((unsigned char)x) #else diff --git a/hdrs/chunk.h b/hdrs/chunk.h index e06ab04..360b580 100644 --- a/hdrs/chunk.h +++ b/hdrs/chunk.h @@ -2,22 +2,23 @@ #ifndef _CHUNK_H_ #define _CHUNK_H_ -#undef LOG_CHUNK_STATS +#ifdef HAVE_STDINT_H +#include +#endif -typedef unsigned short u_int_16; -typedef unsigned int u_int_32; +#undef LOG_CHUNK_STATS -typedef u_int_32 chunk_reference_t; +typedef uint32_t chunk_reference_t; #define NULL_CHUNK_REFERENCE 0 -chunk_reference_t chunk_create(unsigned char const *data, u_int_16 len, - unsigned char derefs); +chunk_reference_t chunk_create(unsigned char const *data, uint16_t len, + uint8_t derefs); void chunk_delete(chunk_reference_t reference); -u_int_16 chunk_fetch(chunk_reference_t reference, - unsigned char *buffer, u_int_16 buffer_len); -u_int_16 chunk_len(chunk_reference_t reference); -unsigned char chunk_derefs(chunk_reference_t reference); -void chunk_migration(int count, chunk_reference_t ** references); +uint16_t chunk_fetch(chunk_reference_t reference, + unsigned char *buffer, uint16_t buffer_len); +uint16_t chunk_len(chunk_reference_t reference); +uint8_t chunk_derefs(chunk_reference_t reference); +void chunk_migration(int count, chunk_reference_t **references); int chunk_num_swapped(void); void chunk_init(void); enum chunk_stats_type { CSTATS_SUMMARY, CSTATS_REGIONG, CSTATS_PAGINGG, diff --git a/hdrs/command.h b/hdrs/command.h index ff8e738..223b51e 100644 --- a/hdrs/command.h +++ b/hdrs/command.h @@ -4,13 +4,18 @@ #include "boolexp.h" #include "division.h" -typedef unsigned char switch_mask[NUM_SWITCH_BYTES]; +typedef uint8_t *switch_mask; +extern int switch_bytes; +#define SW_ALLOC() mush_calloc(switch_bytes, 1, "cmd.switch.vector"); +#define SW_FREE(s) mush_free((s), "cmd.switch.vector"); #define SW_SET(m,n) (m[(n) >> 3] |= (1 << ((n) & 0x7))) #define SW_CLR(m,n) (m[(n) >> 3] &= ~(1 << ((n) & 0x7))) #define SW_ISSET(m,n) (m[(n) >> 3] & (1 << ((n) & 0x7))) -#define SW_ZERO(m) memset(m, 0, NUM_SWITCH_BYTES) +bool SW_BY_NAME(switch_mask, const char *); +#define SW_ZERO(m) memset(m, 0, switch_bytes) +#define SW_COPY(new,old) memcpy((new), (old), switch_bytes) -/* These are type restrictors */ + /* These are type restrictors */ #define CMD_T_ROOM 0x80000000 #define CMD_T_THING 0x40000000 #define CMD_T_EXIT 0x20000000 @@ -91,7 +96,7 @@ typedef unsigned char switch_mask[NUM_SWITCH_BYTES]; #define COMMAND(command_name) \ void command_name (COMMAND_INFO *cmd, dbref player, dbref cause, \ - switch_mask sw,char *raw, char *switches, char *args_raw, \ + switch_mask sw,char *raw, const char *switches, char *args_raw, \ char *arg_left, char *args_left[MAX_ARG], \ char *arg_right, char *args_right[MAX_ARG], int fromport); \ void command_name(COMMAND_INFO *cmd __attribute__ ((__unused__)), \ @@ -99,7 +104,7 @@ void command_name(COMMAND_INFO *cmd __attribute__ ((__unused__)), \ dbref cause __attribute__ ((__unused__)), \ switch_mask sw __attribute__ ((__unused__)), \ char *raw __attribute__ ((__unused__)), \ - char *switches __attribute__ ((__unused__)), \ + const char *switches __attribute__ ((__unused__)), \ char *args_raw __attribute__ ((__unused__)), \ char *arg_left __attribute__ ((__unused__)), \ char *args_left[MAX_ARG] __attribute__ ((__unused__)), \ @@ -109,13 +114,13 @@ void command_name(COMMAND_INFO *cmd __attribute__ ((__unused__)), \ /** Common command prototype macro */ #define COMMAND_PROTO(command_name) \ -void command_name (COMMAND_INFO *cmd, dbref player, dbref cause, switch_mask sw,char *raw, char *switches, char *args_raw, \ +void command_name (COMMAND_INFO *cmd, dbref player, dbref cause, switch_mask sw,char *raw, const char *switches, char *args_raw, \ char *arg_left, char *args_left[MAX_ARG], \ char *arg_right, char *args_right[MAX_ARG], int fromport) typedef struct command_info COMMAND_INFO; typedef void (*command_func) (COMMAND_INFO *, dbref, dbref, switch_mask, char *, - char *, char *, char *, char *[MAX_ARG], char *, + const char *, char *, char *, char *[MAX_ARG], char *, char *[MAX_ARG], int fromport); /** A hook specification. @@ -133,8 +138,12 @@ struct command_info { const char *restrict_message; /**< Message sent when command is restricted */ command_func func; /**< Function to call when command is run */ unsigned int type; /**< Types of objects that can use the command */ - switch_mask sw; /**< Bitflags of switches this command can take */ boolexp lock; + /** Switches for this command. */ + union { + switch_mask mask; /**< Bitflags of switches this command can take */ + const char *names; /**< Space-seperated list of switches */ + } sw; /** Hooks on this command. */ struct { @@ -199,10 +208,10 @@ extern COMMAND_INFO *command_find_exact(const char *name); extern COMMAND_INFO *command_add (const char *name, int type, const char *switchstr, command_func func, const char *command_lock); extern COMMAND_INFO *make_command - (const char *name, int type, switch_mask *sw, command_func func, const char *command_lock); + (const char *name, int type, const char *sw, command_func func, const char *command_lock); extern COMMAND_INFO *command_modify (const char *name, int type, const char *command_lock, - switch_mask *sw, command_func func); + switch_mask sw, command_func func); extern void reserve_alias(const char *a); extern int alias_command(const char *command, const char *alias); extern void command_init_preconfig(void); @@ -220,7 +229,6 @@ extern char *list_commands(void); extern int command_check_byname(dbref player, const char *name); extern int restrict_command(const char *name, const char *restriction); extern void reserve_aliases(void); -extern void local_commands(void); extern void do_command_add(dbref player, char *name, int flags); extern void do_command_delete(dbref player, char *name); extern void generic_command_failure(dbref player, dbref cause, char *string, int fromport); diff --git a/hdrs/compile.h b/hdrs/compile.h index ac7f435..81005bc 100644 --- a/hdrs/compile.h +++ b/hdrs/compile.h @@ -12,35 +12,21 @@ #endif #endif -/* For gcc 3 and up, this attribute lets the compiler know that the +/* For modern gcc , this attribute lets the compiler know that the * function returns a newly allocated value, for pointer aliasing * optimizations. */ -#if !defined(__attribute_malloc__) && __GNUC_PREREQ(2, 96) -#define __attribute_malloc__ __attribute__ ((__malloc__)) +#if !defined(__attribute_malloc__) && defined(GCC_MALLOC_CALL) +#define __attribute_malloc__ GCC_MALLOC_CALL #elif !defined(__attribute_malloc__) #define __attribute_malloc__ #endif -/* The C99 restrict keyword lets the compiler do some more pointer - * aliasing optimizations. Essentially, a RESTRICT pointer function - * argument can't share that pointer with ones passed via other - * arguments. - * This should be a Configure check sometime. - */ -#if __GNUC_PREREQ(2, 92) -#define RESTRICT __restrict -#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L -#define RESTRICT restrict -#else -#define RESTRICT -#endif - /* If a compiler knows a function will never return, it can generate slightly better code for calls to it. */ #if defined(WIN32) && _MSC_VER >= 1200 #define NORETURN __declspec(noreturn) -#elif defined(HASATTRIBUTE) +#elif defined(HAVE___ATTRIBUTE__) #define NORETURN __attribute__ ((__noreturn__)) #else #define NORETURN diff --git a/hdrs/conf.h b/hdrs/conf.h index 211b3ed..b28738a 100644 --- a/hdrs/conf.h +++ b/hdrs/conf.h @@ -1,11 +1,13 @@ /* conf.h */ - -#ifndef __CONF_H -#define __CONF_H +#ifndef __PENNCONF_H +#define __PENNCONF_H #include "copyrite.h" #ifdef I_SYS_TIME #include +#ifdef TIME_WITH_SYS_TIME +#include +#endif #else #include #endif @@ -41,7 +43,6 @@ /* Loose limit on command/function name length */ #define COMMAND_NAME_LIMIT 64 #define MAX_ZONES 30 -#define NUM_SWITCH_BYTES 22 #define MAX_DIVISION_DEPTH 1000 /* magic cookies */ @@ -175,6 +176,7 @@ struct options_table { int max_player_chans; /**< Number of channels a player can create */ int max_channels; /**< Total maximum allowed channels */ int chan_cost; /**< Cost to create a channel */ + int noisy_cemit; /**< Is @cemit noisy by default? */ char connect_file[2][256]; /**< Names of text and html connection files */ char motd_file[2][256]; /**< Names of text and html motd files */ char newuser_file[2][256]; /**< Names of text and html new user files */ @@ -292,13 +294,11 @@ struct options_table { char command_log[256]; /**< File to log suspect commands */ char trace_log[256]; /**< File to log trace data */ char checkpt_log[256]; /**< File to log checkpoint data */ -#ifdef HAS_MYSQL char sql_platform[256]; /**< Type of SQL server, or "disabled" */ char sql_host[256]; /**< Hostname of sql server */ char sql_username[256]; /**< Username for sql */ char sql_password[256]; /**< Password for sql */ char sql_database[256]; /**< Database for sql */ -#endif char guest_prefix[128]; /**< Word used to prefix guest logins */ int guest_roman_numeral; /**< Number guests using roman numerals */ /* Division Related Stuff */ @@ -500,4 +500,4 @@ struct globals_table { extern GLOBALTAB globals; -#endif /* __CONF_H */ +#endif /* __PENN_CONF_H */ diff --git a/hdrs/csrimalloc.h b/hdrs/csrimalloc.h index 36b9544..9140763 100644 --- a/hdrs/csrimalloc.h +++ b/hdrs/csrimalloc.h @@ -63,7 +63,9 @@ univptr_t memalign(size_t alignment, size_t size); univptr_t emalloc(size_t nbytes); univptr_t ecalloc(size_t nelem, size_t sz); univptr_t erealloc(univptr_t ptr, size_t nbytes); +#ifndef HAVE_STRDUP char *strdup(const char *s); +#endif char *strsave(const char *s); void free(univptr_t cp); void cfree(univptr_t cp); diff --git a/hdrs/dbdefs.h b/hdrs/dbdefs.h index 2f7a64f..fbe26f3 100644 --- a/hdrs/dbdefs.h +++ b/hdrs/dbdefs.h @@ -7,8 +7,12 @@ #include #ifdef I_SYS_TIME #include +#ifdef TIME_WITH_SYS_TIME +#include #endif +#else #include +#endif #include "mushdb.h" #include "htab.h" #include "chunk.h" @@ -159,7 +163,7 @@ extern dbref first_free; /* pointer to free list */ #define Loud(x) (has_flag_by_name(x, "LOUD", NOTYPE)) #define Mistrust(x) (has_flag_by_name(x, "MISTRUST", TYPE_THING|TYPE_EXIT|TYPE_ROOM)) #define NoCommand(x) (has_flag_by_name(x, "NO_COMMAND", NOTYPE)) -#define NoWarn(x) (has_flag_by_name(x, "NOWARN", NOTYPE)) +#define NoWarn(x) (has_flag_by_name(x, "NO_WARN", NOTYPE)) #define Opaque(x) (has_flag_by_name(x, "OPAQUE", NOTYPE)) #define Orphan(x) (has_flag_by_name(x, "ORPHAN", NOTYPE)) #define Puppet(x) (has_flag_by_name(x, "PUPPET", TYPE_THING|TYPE_ROOM)) @@ -272,7 +276,7 @@ struct object { dbref owner; /**< who controls this object */ dbref zone; /**< zone master object number */ int penn; /**< number of pennies object contains */ - int warnings; /**< bitflags of warning types */ + warn_type warnings; /**< bitflags of warning types */ time_t creation_time; /**< Time/date of object creation */ /** Last modifiction time. * For players, the number of failed logins. @@ -324,6 +328,8 @@ extern void convert_object_powers(dbref, int); /* the code is in division.c.. #define DOLIST_VISIBLE(var, first, player)\ for((var) = first_visible((player), (first)); GoodObject((var)); (var) = first_visible((player), Next(var))) +typedef uint32_t mail_flag; + /** A mail message. * This structure represents a single mail message in the linked list * of messages that comprises the mail database. Mail messages are @@ -338,7 +344,7 @@ struct mail { chunk_reference_t msgid; /**< Message text, compressed */ time_t time; /**< Message date/time */ unsigned char *subject; /**< Message subject, compressed */ - int read; /**< Bitflags of message status */ + mail_flag read; /**< Bitflags of message status */ }; typedef struct mail MAIL; diff --git a/hdrs/dbio.h b/hdrs/dbio.h index 380daef..d1ec24b 100644 --- a/hdrs/dbio.h +++ b/hdrs/dbio.h @@ -9,6 +9,9 @@ #include #include +#ifdef HAVE_STDINT_H +#include +#endif extern jmp_buf db_err; @@ -19,23 +22,25 @@ extern jmp_buf db_err; /* Output */ extern void putref(FILE * f, long int ref); extern void putstring(FILE * f, const char *s); -extern void db_write_labeled_string(FILE * f, char const *label, - char const *value); -extern void db_write_labeled_number(FILE * f, char const *label, int value); +extern void db_write_labeled_string(FILE * f, char const *label, char const *value); +extern void db_write_labeled_int(FILE * f, char const *label, int value); +extern void db_write_labeld_uint32(FILE *, char const *, uint32_t); extern void db_write_labeled_dbref(FILE * f, char const *label, dbref value); + extern void db_write_flag_db(FILE *); extern dbref db_write(FILE * f, int flag); extern int db_paranoid_write(FILE * f, int flag); /* Input functions */ -extern const char *getstring_noalloc(FILE * f); +extern char *getstring_noalloc(FILE * f); extern long getref(FILE * f); -extern void db_read_this_labeled_string(FILE * f, const char *label, - char **val); +extern void db_read_this_labeled_string(FILE * f, const char *label, char **val); extern void db_read_labeled_string(FILE * f, char **label, char **val); -extern void db_read_this_labeled_number(FILE * f, const char *label, int *val); -extern void db_read_labeled_number(FILE * f, char **label, int *val); +extern void db_read_this_labeled_int(FILE * f, const char *label, int *val); +extern void db_read_this_labeled_uint32(FILE * f, const char *lable, uint32_t * val); +extern void db_read_labeled_int(FILE * f, char **label, int *val); +extern void db_read_labeled_uint32(FILE * f, char **label, uint32_t * val); extern void db_read_this_labeled_dbref(FILE * f, const char *label, dbref *val); extern void db_read_labeled_dbref(FILE * f, char **label, dbref *val); extern int load_flag_db(FILE *); diff --git a/hdrs/extchat.h b/hdrs/extchat.h index 8082031..a011309 100644 --- a/hdrs/extchat.h +++ b/hdrs/extchat.h @@ -26,7 +26,7 @@ * @channel/list do_chan_list() * @channel/add channel do_chan_admin() * @channel/priv channel = do_chan_admin() - * Privlist being: director, admin, private, moderated, etc. + * Privlist being: wizard, admin, private, moderated, etc. * @channel/joinlock channel = lock * @channel/speaklock channel = lock * @channel/modlock channel = lock @@ -41,7 +41,6 @@ #ifndef __EXTCHAT_H #define __EXTCHAT_H -#ifdef CHAT_SYSTEM #include "boolexp.h" #include "bufferq.h" @@ -54,7 +53,7 @@ */ struct chanuser { dbref who; /**< Dbref of joined object */ - long int type; /**< Bitflags for this user */ + privbits type; /**< Bitflags for this user */ char title[CU_TITLE_LEN]; /**< User's channel title */ struct chanuser *next; /**< Pointer to next user in list */ }; @@ -88,14 +87,13 @@ struct chanuser { struct channel { char name[CHAN_NAME_LEN]; /**< Channel name */ char title[CHAN_TITLE_LEN]; /**< Channel description */ - long int type; /**< Channel flags */ - long int cost; /**< What it cost to make this channel */ - long int creator; /**< This is who paid the cost for the channel */ - long int cobj; /**< Channel object or #-1 */ - long int num_users; /**< Number of connected users */ - long int max_users; /**< Maximum allocated users */ + privbits type; /**< Channel flags */ + int cost; /**< What it cost to make this channel */ + dbref creator; /**< This is who paid the cost for the channel */ + int num_users; /**< Number of connected users */ + int max_users; /**< Maximum allocated users */ struct chanuser *users; /**< Linked list of current users */ - long int num_messages; /**< How many messages handled by this chan since startup */ + unsigned long int num_messages; /**< How many messages handled by this chan since startup */ boolexp joinlock; /**< Who may join */ boolexp speaklock; /**< Who may speak */ boolexp modifylock; /**< Who may change things and boot people */ @@ -120,24 +118,23 @@ struct chanlist { /** A structure for passing channel data to notify_anything */ struct na_cpass { CHANUSER *u; /**< Pointer to channel user */ - int checkquiet; /**< Should quiet property be checked? */ + bool checkquiet; /**< Should quiet property be checked? */ }; /* Channel type flags and macros */ -#define CHANNEL_PLAYER 0x1 /* Players may join */ -#define CHANNEL_OBJECT 0x2 /* Objects may join */ -#define CHANNEL_DISABLED 0x4 /* Channel is turned off */ -#define CHANNEL_QUIET 0x8 /* No broadcasts connect/disconnect */ -#define CHANNEL_ADMIN 0x10 /* Admins only */ -#define CHANNEL_DIRECTOR 0x20 /* Directors only */ -#define CHANNEL_CANHIDE 0x40 /* Can non-DARK players hide here? */ -#define CHANNEL_OPEN 0x80 /* Can you speak if you're not joined? */ -#define CHANNEL_NOTITLES 0x100 /* Don't show titles of speakers */ -#define CHANNEL_NONAMES 0x200 /* Don't show names of speakers */ -#define CHANNEL_NOCEMIT 0x400 /* Disallow @cemit */ -#define CHANNEL_COBJ 0x800 /* Channel with a channel object */ -#define CHANNEL_INTERACT 0x1000 /* Filter channel output through interactions */ +#define CHANNEL_PLAYER 0x1U /* Players may join */ +#define CHANNEL_OBJECT 0x2U /* Objects may join */ +#define CHANNEL_DISABLED 0x4U /* Channel is turned off */ +#define CHANNEL_QUIET 0x8U /* No broadcasts connect/disconnect */ +#define CHANNEL_ADMIN 0x10U /* Wizard and royalty only ok */ +#define CHANNEL_DIRECTOR 0x20U /* Wizard only ok */ +#define CHANNEL_CANHIDE 0x40U /* Can non-DARK Wizards hide here? */ +#define CHANNEL_OPEN 0x80U /* Can you speak if you're not joined? */ +#define CHANNEL_NOTITLES 0x100U /* Don't show titles of speakers */ +#define CHANNEL_NONAMES 0x200U /* Don't show names of speakers */ +#define CHANNEL_NOCEMIT 0x400U /* Disallow @cemit */ +#define CHANNEL_INTERACT 0x800U /* Filter channel output through interactions */ #define CHANNEL_DEFAULT_FLAGS (CHANNEL_PLAYER) #define CL_JOIN 0x1 #define CL_SPEAK 0x2 @@ -148,14 +145,10 @@ struct na_cpass { #define MAX_PLAYER_CHANS (options.max_player_chans) #define MAX_CHANNELS (options.max_channels) -const char *ChanObjName _((CHAN *c)); -int ChanObjCheck _((CHAN *c)); #define ChanName(c) ((c)->name) -#define ChanObj(c) ((c)->cobj) #define ChanType(c) ((c)->type) #define ChanTitle(c) ((c)->title) #define ChanCreator(c) ((c)->creator) -#define ChanObj(c) ((c)->cobj) #define ChanCost(c) ((c)->cost) #define ChanNumUsers(c) ((c)->num_users) #define ChanMaxUsers(c) ((c)->max_users) @@ -173,7 +166,7 @@ int ChanObjCheck _((CHAN *c)); #define Channel_Object(c) (ChanType(c) & CHANNEL_OBJECT) #define Channel_Player(c) (ChanType(c) & CHANNEL_PLAYER) #define Channel_Disabled(c) (ChanType(c) & CHANNEL_DISABLED) -#define Channel_Director(c) (ChanType(c) & CHANNEL_DIRECTOR) +#define Channel_Wizard(c) (ChanType(c) & CHANNEL_DIRECTOR) #define Channel_Admin(c) (ChanType(c) & CHANNEL_ADMIN) #define Channel_CanHide(c) (ChanType(c) & CHANNEL_CANHIDE) #define Channel_NoTitles(c) (ChanType(c) & CHANNEL_NOTITLES) @@ -181,34 +174,34 @@ int ChanObjCheck _((CHAN *c)); #define Channel_NoCemit(c) (ChanType(c) & CHANNEL_NOCEMIT) #define Channel_Interact(c) (ChanType(c) & CHANNEL_INTERACT) #define Chan_Ok_Type(c,o) \ - ((ChanObj(c) == o) || (IsPlayer(o) && Channel_Player(c)) || \ + ((IsPlayer(o) && Channel_Player(c)) || \ (IsThing(o) && Channel_Object(c))) #define Chan_Can(p,t) \ - (!(t & CHANNEL_DISABLED) && (!(t & CHANNEL_DIRECTOR) || Director(p)) || \ - (!(t & CHANNEL_ADMIN) || Admin(p) || div_powover(p,p,"Chat"))) + (!(t & CHANNEL_DISABLED) && (!(t & CHANNEL_DIRECTOR) || Director(p)) || \ + (!(t & CHANNEL_ADMIN) || Admin(p) || div_powover(p,p,"Chat"))) /* Who can change channel privileges to type t */ -#define Chan_Can_Priv(p,t,c) (!((t & CHANNEL_COBJ) && !(c & CHANNEL_COBJ)) && !(!(t & CHANNEL_COBJ) && (c & CHANNEL_COBJ)) && Chan_Can(p,t)) +#define Chan_Can_Priv(p,t) (Chan_Can(p,t)) #define Chan_Can_Access(c,p) (Chan_Can(p,ChanType(c))) #define Chan_Can_Join(c,p) \ (Chan_Can_Access(c,p) && \ - (eval_chan_lock(c,p,CLOCK_JOIN))) + (eval_chan_lock(c,p, CLOCK_JOIN))) #define Chan_Can_Speak(c,p) \ (Chan_Can_Access(c,p) && \ - (Loud(p) || eval_chan_lock(c,p, CLOCK_SPEAK))) + (eval_chan_lock(c,p, CLOCK_SPEAK))) #define Chan_Can_Cemit(c,p) \ (!Channel_NoCemit(c) && Chan_Can_Speak(c,p)) #define Chan_Can_Modify(c,p) \ - ((ChanCreator(c) == (p) || Director(p)) || \ + (Director(p) || (ChanCreator(c) == (p)) || \ (!Guest(p) && Chan_Can_Access(c,p) && \ - (eval_chan_lock(c,p,CLOCK_MOD)))) + (eval_chan_lock(c,p, CLOCK_MOD)))) #define Chan_Can_See(c,p) \ - ((Admin(p) || See_All(p)) || (Chan_Can_Access(c,p) && \ - (eval_chan_lock(c,p,CLOCK_SEE)))) + ((Admin(p) || See_All(p)) || (Chan_Can_Access(c,p) && \ + (eval_chan_lock(c,p,CLOCK_SEE)))) #define Chan_Can_Hide(c,p) \ (Can_Hide(p) || (Channel_CanHide(c) && Chan_Can_Access(c,p) && \ - (eval_chan_lock(c,p,CLOCK_HIDE)))) + (eval_chan_lock(c,p, CLOCK_HIDE)))) #define Chan_Can_Nuke(c,p) (ChanCreator(c) == (p) || div_powover(p, ChanCreator(c), "Chat")) -#define Chan_Can_Decomp(c,p) (See_All(p) || (ChanCreator(c) == (p))) +#define Chan_Can_Decomp(c,p) (Director(p) || (ChanCreator(c) == (p))) @@ -218,15 +211,16 @@ enum cmatch_type { CMATCH_NONE, CMATCH_EXACT, CMATCH_PARTIAL, CMATCH_AMBIG }; /* Some globals */ extern int num_channels; -extern void WIN32_CDECL channel_broadcast - (CHAN *channel, dbref player, int flags, const char *fmt, ...) - __attribute__ ((__format__(__printf__, 4, 5))); +extern void WIN32_CDECL channel_chat + (CHAN *channel, dbref player, int flags, const char *message, char type, + const char *fmt, ...) + __attribute__ ((__format__(__printf__, 6, 7))); extern CHANUSER *onchannel(dbref who, CHAN *c); extern void init_chatdb(void); extern int load_chatdb(FILE * fp); extern int save_chatdb(FILE * fp); extern void do_cemit - (dbref player, const char *name, const char *msg, int noisy); + (dbref player, const char *name, const char *msg, int flags); extern void do_chan_user_flags (dbref player, char *name, const char *isyn, int flag, int silent); extern void do_chan_wipe(dbref player, const char *name); @@ -265,5 +259,4 @@ enum chan_match_type { }; -#endif /* CHAT_SYSTEM */ #endif /* __EXTCHAT_H */ diff --git a/hdrs/externs.h b/hdrs/externs.h index 1302f2c..e822a7e 100644 --- a/hdrs/externs.h +++ b/hdrs/externs.h @@ -6,7 +6,6 @@ * */ - #ifndef __EXTERNS_H #define __EXTERNS_H /* Get the time_t definition that we use in prototypes here */ @@ -14,7 +13,7 @@ #ifdef I_LIBINTL #include #endif -#if defined(HAS_GETTEXT) && !defined(DONT_TRANSLATE) +#if defined(HAVE_GETTEXT) && !defined(DONT_TRANSLATE) /** Macro for a translated string */ #define T(str) gettext(str) /** Macro to note that a string has a translation but not to translate */ @@ -29,13 +28,21 @@ #include "mushtype.h" #include "dbdefs.h" #include "confmagic.h" -#ifndef HAS_STRCASECMP -#ifdef WIN32 +#include "mypcre.h" + +#ifndef HAVE_STRCASECMP +#ifdef HAVE__STRICMP #define strcasecmp(s1,s2) _stricmp((s1), (s2)) +#else +int strcasecmp(const char *s1, const char *s2); +#endif +#endif + +#ifndef HAVE_STRNCASECMP +#ifdef HAVE__STRNICMP #define strncasecmp(s1,s2,n) _strnicmp((s1), (s2), (n)) #else -extern int strcasecmp(const char *s1, const char *s2); -extern int strncasecmp(const char *s1, const char *s2, size_t n); +int strncasecmp(const char *s1, const char *s2, size_t n); #endif #endif @@ -89,6 +96,15 @@ extern void init_timer(void); /* From attrib.c */ extern dbref atr_on_obj; +extern bool can_edit_attr(dbref player, dbref thing, const char *attrname); + +/* From log.c */ +void penn_perror(const char *); + +/* From wait.c */ +int lock_file(FILE *); +int unlock_file(FILE *); + /* From bsd.c */ extern FILE *connlog_fp; @@ -98,12 +114,12 @@ extern FILE *tracelog_fp; extern FILE *cmdlog_fp; extern int restarting; #ifdef SUN_OS -extern int f_close(FILE * file); +int f_close(FILE * file); /** SunOS fclose macro */ #define fclose(f) f_close(f); #endif -extern int hidden(dbref player); -extern dbref guest_to_connect(dbref player); +int hidden(dbref player); +dbref guest_to_connect(dbref player); void dump_reboot_db(void); void close_ssl_connections(void); int least_idle_time(dbref player); @@ -115,7 +131,7 @@ char *least_idle_hostname(dbref player); extern int do_command(DESC *d, char *command); /* sql.c */ -extern void sql_shutdown(void); +void sql_shutdown(void); /* The #defs for our notify_anything hacks.. Errr. Functions */ #define NA_NORELAY 0x0001 /**< Don't relay sound */ @@ -179,7 +195,14 @@ extern char *ns_esnotify(dbref speaker, na_lookup func, void *fdata, int para); #define notify_noecho(p,m) notify_anything(orator, na_one, &(p), NULL, NA_NORELAY | NA_PUPPET, m) /** Notify player with message if they're not set QUIET */ #define quiet_notify(p,m) if (!IsQuiet(p)) notify(p,m) -extern void notify_format(dbref player, const char *fmt, ...) +/** Notify player but don't send \n */ +#define notify_noenter_by(t,a,b) notify_anything(t, na_one, &(a), NULL, NA_NOENTER, b) +#define notify_noenter(a,b) notify_noenter_by(GOD, a, b) +/** Notify player but don't send
if they're using Pueblo */ +#define notify_nopenter_by(t,a,b) notify_anything(t, na_one, &(a), NULL, NA_NOPENTER, b) +#define notify_nopenter(a,b) notify_nopenter_by(GOD, a, b) +/* Notify with a printf-style format */ +void notify_format(dbref player, const char *fmt, ...) __attribute__ ((__format__(__printf__, 2, 3))); /* From compress.c */ @@ -188,11 +211,13 @@ extern void notify_format(dbref player, const char *fmt, ...) */ /* #define COMP_STATS /* */ #if (COMPRESSION_TYPE != 0) -extern unsigned char * -compress(char const *s) +unsigned char * +text_compress(char const *s) __attribute_malloc__; - extern char *uncompress(unsigned char const *s); - extern char *safe_uncompress(unsigned char const *s) __attribute_malloc__; +#define compress(str) text_compress(str) + char *text_uncompress(unsigned char const *s); +#define uncompress(str) text_uncompress(str) + char *safe_uncompress(unsigned char const *s) __attribute_malloc__; #else extern char ucbuff[]; #define init_compress(f) 0 @@ -202,6 +227,7 @@ extern char ucbuff[]; #endif /* From cque.c */ +struct _ansi_string; struct real_pcre; struct eval_context { char *wenv[10]; /**< working environment (%0-%9) */ @@ -217,8 +243,7 @@ struct eval_context { struct real_pcre *re_code; /**< The compiled re */ int re_subpatterns; /**< The number of re subpatterns */ int *re_offsets; /**< The offsets for the subpatterns */ - char *re_from; /**< The positions of the subpatterns */ - HASHTAB namedregs; + struct _ansi_string *re_from; /**< The positions of the subpatterns */ HASHTAB namedregs; HASHTAB namedregsnxt; }; @@ -251,6 +276,14 @@ extern void dequeue_semaphores(dbref thing, char const *aname, int count, extern void shutdown_queues(void); extern void do_hourly(void); +/* Regexp saving helpers */ +struct re_save { + struct real_pcre *re_code; /**< The compiled re */ + int re_subpatterns; /**< The number of re subpatterns */ + int *re_offsets; /**< The offsets for the subpatterns */ + struct _ansi_string *re_from; /**< The positions of the subpatterns */ +}; + extern void init_namedregs(HASHTAB *); extern void free_namedregs(HASHTAB *); extern void clear_namedregs(HASHTAB *); @@ -291,55 +324,59 @@ void release_fd(void); enum look_type { LOOK_NORMAL, LOOK_TRANS, LOOK_AUTO, LOOK_CLOUDYTRANS, LOOK_CLOUDY }; -extern void look_room(dbref player, dbref loc, enum look_type style); -extern void do_look_around(dbref player); -extern void do_look_at(dbref player, const char *name, int key); -extern char *decompose_str(char *what); +void look_room(dbref player, dbref loc, enum look_type style); +void do_look_around(dbref player); +void do_look_at(dbref player, const char *name, int key); +char *decompose_str(char *what); /* From memcheck.c */ -extern void add_check(const char *ref); -extern void del_check(const char *ref); -extern void list_mem_check(dbref player); -extern void log_mem_check(void); +void add_check(const char *ref); +void del_check(const char *ref, const char *filename, int line); +void list_mem_check(dbref player); +void log_mem_check(void); /* From move.c */ -extern void enter_room(dbref player, dbref loc, int nomovemsgs); -extern int can_move(dbref player, const char *direction); +void enter_room(dbref player, dbref loc, int nomovemsgs); +int can_move(dbref player, const char *direction); /** Enumeration of types of movements that can be performed */ enum move_type { MOVE_NORMAL, MOVE_GLOBAL, MOVE_ZONE }; -extern void do_move(dbref player, const char *direction, enum move_type type); -extern void moveto(dbref what, dbref where); -extern void safe_tel(dbref player, dbref dest, int nomovemsgs); -extern int global_exit(dbref player, const char *direction); -extern int remote_exit(dbref loc, const char *direction); -extern void move_wrapper(dbref player, const char *command); -extern void do_follow(dbref player, const char *arg); -extern void do_unfollow(dbref player, const char *arg); -extern void do_desert(dbref player, const char *arg); -extern void do_dismiss(dbref player, const char *arg); -extern void clear_followers(dbref leader, int noisy); -extern void clear_following(dbref follower, int noisy); +void do_move(dbref player, const char *direction, enum move_type type); +void moveto(dbref what, dbref where); +void safe_tel(dbref player, dbref dest, int nomovemsgs); +int global_exit(dbref player, const char *direction); +int remote_exit(dbref loc, const char *direction); +void move_wrapper(dbref player, const char *command); +void do_follow(dbref player, const char *arg); +void do_unfollow(dbref player, const char *arg); +void do_desert(dbref player, const char *arg); +void do_dismiss(dbref player, const char *arg); +void clear_followers(dbref leader, int noisy); +void clear_following(dbref follower, int noisy); /* From mycrypt.c */ -extern char *mush_crypt(const char *key); +char *mush_crypt(const char *key); /* From player.c */ -extern int password_check(dbref player, const char *password); -extern dbref lookup_player(const char *name); -extern dbref lookup_player_name(const char *name); +int password_check(dbref player, const char *password); +dbref lookup_player(const char *name); +dbref lookup_player_name(const char *name); /* from player.c */ -extern dbref create_player(const char *name, const char *password, - const char *host, const char *ip); -extern dbref connect_player(const char *name, const char *password, - const char *host, const char *ip, char *errbuf); -extern void check_last(dbref player, const char *host, const char *ip); -extern void check_lastfailed(dbref player, const char *host); +dbref create_player(const char *name, const char *password, + const char *host, const char *ip); +dbref connect_player(const char *name, const char *password, + const char *host, const char *ip, char *errbuf); +void check_last(dbref player, const char *host, const char *ip); +void check_lastfailed(dbref player, const char *host); /* From parse.c */ -extern int is_number(const char *str); -extern int is_strict_number(const char *str); -extern int is_strict_integer(const char *str); -int is_good_number(double); +bool is_number(const char *str); +bool is_strict_number(const char *str); +bool is_strict_integer(const char *str); +#ifdef HAVE_ISNORMAL +#define is_good_number(n) isnormal((n)) +#else +bool is_good_number(NVAL val); +#endif /* From plyrlist.c */ void clear_players(void); @@ -386,7 +423,7 @@ extern int ok_player_name(const char *name, dbref player, dbref thing); extern int ok_player_alias(const char *alias, dbref player, dbref thing); extern int ok_password(const char *password); extern int ok_tag_attribute(dbref player, char *params); -extern dbref parse_match_possessor(dbref player, const char **str); +extern dbref parse_match_possessor(dbref player, char **str); extern void page_return(dbref player, dbref target, const char *type, const char *message, const char *def); extern char *grep_util(dbref player, dbref thing, char *pattern, @@ -451,15 +488,16 @@ extern char *strinitial(const char *s); extern char *upcasestr(char *s); extern char *skip_space(const char *s); extern char *seek_char(const char *s, char c); -extern int u_strlen(const unsigned char *s); -extern unsigned char *u_strcpy - (unsigned char *target, const unsigned char *source); +extern size_t u_strlen(const unsigned char *s); +extern unsigned char *u_strncpy + (unsigned char *restrict target, const unsigned char *restrict source, + size_t len); + /** Unsigned char strdup */ #define u_strdup(x) (unsigned char *)strdup((char *) x) -#ifndef HAS_STRDUP +#ifndef HAVE_STRDUP char * -strdup(const char *s) - __attribute_malloc__; +strdup(const char *s) __attribute_malloc__; #endif char *mush_strdup(const char *s, const char *check) __attribute_malloc__; #ifdef WIN32 @@ -468,22 +506,7 @@ strdup(const char *s) #define vsnprintf _vsnprintf #endif #endif - extern char *remove_markup(const char *orig, size_t * stripped_len); - extern char *skip_leading_ansi(const char *s); - -/** A string, with ansi attributes broken out from the text */ - typedef struct { - char text[BUFFER_LEN]; /**< Text of the string */ - char *codes[BUFFER_LEN]; /**< Ansi codes associated with each char of text */ - size_t len; /**< Length of text */ - } ansi_string; - - extern ansi_string *parse_ansi_string(const char *src) __attribute_malloc__; - extern void flip_ansi_string(ansi_string *as); - extern void free_ansi_string(ansi_string *as); - extern void populate_codes(ansi_string *as); - extern void depopulate_codes(ansi_string *as); #ifdef WIN32 #define strncoll(s1,s2,n) _strncoll((s1), (s2), (n)) #define strcasecoll(s1,s2) _stricoll((s1), (s2)) @@ -504,11 +527,11 @@ strdup(const char *s) extern int safe_format(char *buff, char **bp, const char *RESTRICT fmt, ...) __attribute__ ((__format__(__printf__, 3, 4))); /* Append an int to the end of a buffer */ - extern int safe_integer(long i, char *buff, char **bp); - extern int safe_uinteger(unsigned long, char *buff, char **bp); + extern int safe_integer(intmax_t i, char *buff, char **bp); + extern int safe_uinteger(uintmax_t, char *buff, char **bp); /* Same, but for a SBUF_LEN buffer, not BUFFER_LEN */ #define SBUF_LEN 64 /**< A short buffer */ - extern int safe_integer_sbuf(long i, char *buff, char **bp); + extern int safe_integer_sbuf(intmax_t i, char *buff, char **bp); /* Append a NVAL to a string */ extern int safe_number(NVAL n, char *buff, char **bp); /* Append a dbref to a buffer */ @@ -518,14 +541,10 @@ strdup(const char *s) /* Append a string to a buffer, sticking it in quotes if there's a space */ extern int safe_str_space(const char *s, char *buff, char **bp); /* Append len characters of a string to a buffer */ - extern int safe_strl(const char *s, int len, char *buff, char **bp); + extern int safe_strl(const char *s, size_t len, char *buff, char **bp); /** Append a boolean to the end of a string */ #define safe_boolean(x, buf, bufp) \ safe_chr((x) ? '1' : '0', (buf), (bufp)) -/* Append X characters to the end of a string, taking ansi and html codes into - account. */ -extern int safe_ansi_string(ansi_string *as, size_t start, size_t len, char *buff, char **bp); -extern int safe_ansi_string2(ansi_string *as, size_t start, size_t len, char *buff, char **bp); /* Append N copies of the character X to the end of a string */ extern int safe_fill(char x, size_t n, char *buff, char **bp); @@ -550,7 +569,7 @@ extern int safe_ansi_string2(ansi_string *as, size_t start, size_t len, char *bu extern void safe_itemizer(int cur_num, int done, const char *delim, const char *conjoin, const char *space, char *buff, char **bp); - extern char *show_time(time_t t, int utc); + extern char *show_time(time_t t, bool utc); extern char *show_tm(struct tm *t); @@ -562,8 +581,8 @@ extern int safe_ansi_string2(ansi_string *as, size_t start, size_t len, char *bu extern accent_info accent_table[]; - extern int ansi_strlen(const char *string); - extern int ansi_strnlen(const char *string, size_t numchars); + int ansi_strlen(const char *string); + int ansi_strnlen(const char *string, size_t numchars); /* From unparse.c */ const char *real_unparse @@ -572,68 +591,78 @@ extern int safe_ansi_string2(ansi_string *as, size_t start, size_t len, char *bu extern const char *unparse_object(dbref player, dbref loc); /** For back compatibility, an alias for unparse_object */ #define object_header(p,l) unparse_object(p,l) - extern const char *unparse_object_myopic(dbref player, dbref loc); - extern const char *unparse_room(dbref player, dbref loc); - extern int nameformat(dbref player, dbref loc, char *tbuf1, char *defname); - extern const char *accented_name(dbref thing); + const char *unparse_object_myopic(dbref player, dbref loc); + const char *unparse_room(dbref player, dbref loc); + int nameformat(dbref player, dbref loc, char *tbuf1, char *defname); + const char *accented_name(dbref thing); /* From utils.c */ - extern void parse_attrib(dbref player, char *str, dbref *thing, - ATTR **attrib); - extern void parse_anon_attrib(dbref player, char *str, dbref *thing, - ATTR **attrib); - extern void free_anon_attrib(ATTR *attrib); + void parse_attrib(dbref player, char *str, dbref *thing, ATTR **attrib); + void parse_anon_attrib(dbref player, char *str, dbref *thing, + ATTR **attrib); + void free_anon_attrib(ATTR *attrib); typedef struct _ufun_attrib { dbref thing; char contents[BUFFER_LEN]; int pe_flags; char *errmess; } ufun_attrib; - extern int fetch_ufun_attrib(char *attrname, dbref executor, - ufun_attrib * ufun, int accept_lambda); - extern int call_ufun(ufun_attrib * ufun, char **wenv_args, int wenv_argc, - char *ret, dbref executor, dbref enactor, - PE_Info * pe_info); - extern int member(dbref thing, dbref list); - extern int recursive_member(dbref disallow, dbref from, int count); - extern dbref remove_first(dbref first, dbref what); - extern dbref reverse(dbref list); - extern Malloc_t mush_malloc(size_t size, - const char *check) __attribute_malloc__; - extern void mush_free(Malloc_t RESTRICT ptr, const char *RESTRICT check); - extern long get_random_long(long low, long high); - extern char *fullalias(dbref it); - extern char *shortalias(dbref it); - extern char *shortname(dbref it); - extern dbref absolute_room(dbref it); + bool fetch_ufun_attrib(char *attrname, dbref executor, + ufun_attrib * ufun, bool accept_lambda); + bool call_ufun(ufun_attrib * ufun, char **wenv_args, int wenv_argc, + char *ret, dbref executor, dbref enactor, PE_Info *pe_info); + bool call_attrib(dbref thing, const char *attrname, + const char *wenv_args[], int wenv_argc, char *ret, + dbref enactor, PE_Info *pe_info); + bool member(dbref thing, dbref list); + bool recursive_member(dbref disallow, dbref from, int count); + dbref remove_first(dbref first, dbref what); + dbref reverse(dbref list); + void *mush_malloc(size_t bytes, const char *check) __attribute_malloc__; + void *mush_calloc(size_t count, size_t size, + const char *check) __attribute_malloc__; +#define mush_realloc(ptr, size, tag) \ + mush_realloc_where((ptr), (size), (tag), __FILE__, __LINE__) + void *mush_realloc_where(void *restrict ptr, size_t newsize, + const char *restrict check, + const char *restrict filename, int line); +#define mush_free(ptr,tag) mush_free_where((ptr), (tag), __FILE__, __LINE__) + void mush_free_where(void *restrict ptr, const char *restrict check, + const char *restrict filename, int line); + long get_random_long(long low, long high); + char *fullalias(dbref it); + char *shortalias(dbref it); + char *shortname(dbref it); + dbref absolute_room(dbref it); int can_interact(dbref from, dbref to, int type); /* From warnings.c */ - extern void run_topology(void); - extern void do_warnings(dbref player, const char *name, const char *warns); - extern void do_wcheck(dbref player, const char *name); - extern void do_wcheck_me(dbref player); - extern void do_wcheck_all(dbref player); - extern void set_initial_warnings(dbref player); - extern const char *unparse_warnings(warn_type warnings); - extern warn_type parse_warnings(dbref player, const char *warnings); + void run_topology(void); + void do_warnings(dbref player, const char *name, const char *warns); + void do_wcheck(dbref player, const char *name); + void do_wcheck_me(dbref player); + void do_wcheck_all(dbref player); + void set_initial_warnings(dbref player); + const char *unparse_warnings(warn_type warnings); + warn_type parse_warnings(dbref player, const char *warnings); /* From wild.c */ - extern int local_wild_match_case(const char *RESTRICT s, - const char *RESTRICT d, int cs); - extern int wildcard(const char *s); - extern int quick_wild_new(const char *RESTRICT tstr, - const char *RESTRICT dstr, int cs); - extern int regexp_match_case_r(const char *RESTRICT s, - const char *RESTRICT d, int cs, char **, int, - char *, int); - extern int quick_regexp_match(const char *RESTRICT s, - const char *RESTRICT d, int cs); - extern int wild_match_case_r(const char *RESTRICT s, const char *RESTRICT d, - int cs, char **, int, char *, int); - extern int quick_wild(const char *RESTRICT tsr, const char *RESTRICT dstr); - extern int atr_wild(const char *RESTRICT tstr, const char *RESTRICT dstr); + bool local_wild_match_case(const char *restrict s, + const char *restrict d, bool cs); + bool wildcard(const char *s); + bool quick_wild_new(const char *restrict tstr, + const char *restrict dstr, bool cs); + bool regexp_match_case_r(const char *restrict s, const char *restrict d, + bool cs, char **, size_t, char *restrict, ssize_t); + bool quick_regexp_match(const char *restrict s, + const char *restrict d, bool cs); + bool qcomp_regexp_match(const pcre * re, const char *s); + bool wild_match_case_r(const char *restrict s, + const char *restrict d, bool cs, + char **ary, size_t max, char *ata, ssize_t len); + bool quick_wild(const char *restrict tsr, const char *restrict dstr); + bool atr_wild(const char *restrict tstr, const char *restrict dstr); /** Default (case-insensitive) local wildcard match */ #define local_wild_match(s,d) local_wild_match_case(s, d, 0) @@ -657,6 +686,7 @@ extern int safe_ansi_string2(ansi_string *as, size_t start, size_t len, char *bu /* From function.c and other fun*.c */ extern char *strip_braces(char const *line); + void save_regexp_context(struct re_save *); extern void save_global_regs(const char *funcname, char *preserve[]); extern void restore_global_regs(const char *funcname, char *preserve[]); extern void free_global_regs(const char *funcname, char *preserve[]); @@ -677,7 +707,7 @@ extern int safe_ansi_string2(ansi_string *as, size_t start, size_t len, char *bu const char *aname); extern char *ArabicToRoman(int); extern int RomanToArabic(char *); - + extern void restore_regexp_context(struct re_save *); /* From destroy.c */ void do_undestroy(dbref player, char *name); dbref free_get(void); diff --git a/hdrs/extmail.h b/hdrs/extmail.h index 1965fe9..6a2ca86 100644 --- a/hdrs/extmail.h +++ b/hdrs/extmail.h @@ -3,21 +3,21 @@ #ifndef _EXTMAIL_H #define _EXTMAIL_H /* Some of this isn't implemented yet, but heralds the future! */ -#define M_MSGREAD 0x0001 -#define M_UNREAD 0x0FFE -#define M_CLEARED 0x0002 -#define M_URGENT 0x0004 -#define M_MASS 0x0008 -#define M_EXPIRE 0x0010 -#define M_RECEIPT 0x0020 -#define M_TAG 0x0040 -#define M_FORWARD 0x0080 +#define M_MSGREAD 0x0001U +#define M_UNREAD 0x0FFEU +#define M_CLEARED 0x0002U +#define M_URGENT 0x0004U +#define M_MASS 0x0008U +#define M_EXPIRE 0x0010U +#define M_RECEIPT 0x0020U +#define M_TAG 0x0040U +#define M_FORWARD 0x0080U /* 0x0100 - 0x0F00 reserved for folder numbers */ -#define M_FMASK 0xF0FF -#define M_ALL 0x1000 /* In mail_selector, all msgs in all folders */ -#define M_MSUNREAD 0x2000 /* Mail selectors */ -#define M_REPLY 0x4000 -#define M_FOLDER 0x8000 /* In mail selector, all msgs in cur folder */ +#define M_FMASK 0xF0FFU +#define M_ALL 0x1000U /* In mail_selector, all msgs in all folders */ +#define M_MSUNREAD 0x2000U /* Mail selectors */ +#define M_REPLY 0x4000U +#define M_FOLDER 0x8000U /* In mail selector, all msgs in cur folder */ /* 0x4000 - 0x8000 available */ #define MAX_FOLDERS 15 @@ -30,7 +30,7 @@ #define Forward(m) (m->read & M_FORWARD) #define Reply(m) (m->read & M_REPLY) #define Tagged(m) (m->read & M_TAG) -#define Folder(m) ((m->read & ~M_FMASK) >> 8) +#define Folder(m) ((m->read & ~M_FMASK) >> 8U) #define Read(m) (m->read & M_MSGREAD) #define Cleared(m) (m->read & M_CLEARED) #define Unread(m) (!Read(m)) @@ -38,8 +38,6 @@ #define AllInFolder(ms) (ms.flags & M_FOLDER) #define MSFolder(ms) ((int)((ms.flags & ~M_FMASK) >> 8U)) -typedef unsigned int mail_flag; - /** A mail selection. * This structure maintains information about a selected list of * messages. Messages can be selected in several ways. @@ -100,9 +98,4 @@ extern void do_mail_send (dbref player, char *tolist, char *message, mail_flag flags, int silent, int nosig); -/* From bsd.c */ -extern struct mail *desc_mail(dbref player); -extern void desc_mail_set(dbref player, struct mail *mp); -extern void desc_mail_clear(void); - #endif /* _EXTMAIL_H */ diff --git a/hdrs/flags.h b/hdrs/flags.h index 7ac19a9..601ae56 100644 --- a/hdrs/flags.h +++ b/hdrs/flags.h @@ -1,6 +1,7 @@ -/* flags.h */ - -/* flag and powers stuff */ +/** \file flags.h + * + * \brief flag and powers stuff + */ #ifndef __FLAGS_H #define __FLAGS_H @@ -20,8 +21,8 @@ struct flag_info { char letter; /**< Flag character, which may be nul */ int type; /**< Bitflags of object types this flag applies to */ int bitpos; /**< Bit position assigned to this flag for now */ - int perms; /**< Bitflags of who can set this flag */ - int negate_perms; /**< Bitflags of who can clear this flag */ + uint32_t perms; /**< Bitflags of who can set this flag */ + uint32_t negate_perms; /**< Bitflags of who can clear this flag */ }; typedef struct flag_alias FLAG_ALIAS; @@ -133,17 +134,18 @@ extern void decompile_flags(dbref player, dbref thing, const char *name); * Flag permissions */ -#define F_ANY 0x10 /* can be set by anyone - obsolete now */ -#define F_OWNED 0x40 /* can be set on owned objects */ -#define F_PRIVILEGE 0x80 /* can only be set by privileged players */ -#define F_GOD 0x200 /* can only be set by God */ -#define F_INTERNAL 0x400 /* only the game can set this */ -#define F_DARK 0x800 /* only God can see this flag */ -#define F_MDARK 0x1000 /* admin/God can see this flag */ -#define F_ODARK 0x2000 /* owner/admin/God can see this flag */ -#define F_DISABLED 0x4000 /* flag can't be used */ -#define F_LOG 0x8000 -#define F_SELF 0x10000 /* can set on self, regardless of the above */ +#define F_ANY 0x10U /* can be set by anyone - obsolete now */ +#define F_OWNED 0x40U /* can be set on owned objects */ +#define F_PRIVILEGE 0x80U /* can only be set by privileged players */ +#define F_GOD 0x200U /* can only be set by God */ +#define F_INTERNAL 0x400U /* only the game can set this */ +#define F_DARK 0x800U /* only God can see this flag */ +#define F_MDARK 0x1000U /* admin/God can see this flag */ +#define F_ODARK 0x2000U /* owner/admin/God can see this flag */ +#define F_DISABLED 0x4000U /* flag can't be used */ +#define F_LOG 0x8000U +#define F_SELF 0x10000U /* can set on self, regardless of the above */ +#define F_MAX 0x00800000U /**< Largest allowed flag bit */ /* Flags can be in the flaglist multiple times, thanks to aliases. Keep * a reference count of how many times, and free memory when it goes to 0. */ @@ -151,10 +153,10 @@ extern void decompile_flags(dbref player, dbref thing, const char *name); #define F_REF_NOT 0x00FFFFFF /**< Everything but */ #define FLAG_REF(r) (((r) & F_REF_MASK) >> 30) #define ZERO_FLAG_REF(r) ((r) & F_REF_NOT) -#define INCR_FLAG_REF(r) (ZERO_FLAG_REF((r)) | (((r) & F_REF_MASK) + (1 << 30))) -#define DECR_FLAG_REF(r) (ZERO_FLAG_REF((r)) | (((r) & F_REF_MASK) - (1 << 30))) +#define INCR_FLAG_REF(r) ((r) + (1 << 30)) +#define DECR_FLAG_REF(r) ((r) - (1 << 30)) -/* we don't use these anymore.. but kept aroudn for DB conversion */ + /* we don't use these anymore.. but kept aroudn for DB conversion */ /*-------------------------------------------------------------------------- * Powers table diff --git a/hdrs/function.h b/hdrs/function.h index 34adc77..556039a 100644 --- a/hdrs/function.h +++ b/hdrs/function.h @@ -35,8 +35,9 @@ #define FN_LOGARGS 0x2000 /* Localize function registers */ #define FN_LOCALIZE 0x4000 -#define FN_NORP 0x8000 -#define FN_ONEARG 0x10000 +#define FN_NORP 0x8000 +#define FN_ONEARG 0x10000 +#define FN_USERFN 0x20000 /* Allowed in @function only */ #ifndef HAVE_FUN_DEFINED @@ -88,26 +89,27 @@ struct userfn_entry { extern USERFN_ENTRY *userfn_tab; -extern void do_userfn(char *buff, char **bp, - dbref obj, ATTR *attrib, - int nargs, char **args, - dbref executor, dbref caller, dbref enactor, - PE_Info * pe_info); +void do_userfn(char *buff, char **bp, + dbref obj, ATTR *attrib, + int nargs, char **args, + dbref executor, dbref caller, dbref enactor, + PE_Info *pe_info, int extra_flags); -extern FUN *func_hash_lookup(const char *name); -extern int check_func(dbref player, FUN *fp); -extern int restrict_function(const char *name, const char *restrict); -extern int alias_function(const char *function, const char *alias); -extern void do_function_restrict(dbref player, const char *name, - const char *restrict); -extern void do_function_restore(dbref player, const char *name); -extern void do_list_functions(dbref player, int lc); -extern char *list_functions(void); -extern void do_function(dbref player, char *name, char **argv, int preserve); -extern void do_function_toggle(dbref player, char *name, int toggle); -extern void do_function_report(dbref player, char *name); -extern void do_function_delete(dbref player, char *name); -extern void function_init_postconfig(void); +FUN *func_hash_lookup(const char *name); +FUN *builtin_func_hash_lookup(const char *name); +int check_func(dbref player, FUN *fp); +int restrict_function(const char *name, const char *restrict); +int alias_function(const char *function, const char *alias); +void do_function_restrict(dbref player, const char *name, + const char *restrict, int builtin); +void do_function_restore(dbref player, const char *name); +void do_list_functions(dbref player, int lc); +char *list_functions(const char *); +void do_function(dbref player, char *name, char **argv, int preserve); +void do_function_toggle(dbref player, char *name, int toggle); +void do_function_report(dbref player, char *name); +void do_function_delete(dbref player, char *name); +void function_init_postconfig(void); #define FUNCTION_PROTO(fun_name) \ diff --git a/hdrs/game.h b/hdrs/game.h index c686d53..65856af 100644 --- a/hdrs/game.h +++ b/hdrs/game.h @@ -14,11 +14,9 @@ /* hash table stuff */ extern void init_func_hashtab(void); /* eval.c */ -extern void init_math_hashtab(void); /* funmath.c */ extern void init_aname_table(void); /* atr_tab.c */ extern void init_flagspaces(void); /* flags.c */ extern void init_flag_table(const char *ns); /* flags.c */ -extern void init_tag_hashtab(void); /* funstr.c */ extern void init_pronouns(void); /* funstr.c */ /* From bsd.c */ @@ -30,10 +28,12 @@ extern void do_motd(dbref player, enum motd_type key, const char *message); extern void do_poll(dbref player, const char *message, int clear); /* From cque.c */ extern int do_wait - (dbref player, dbref cause, char *arg1, char *cmd, int until, char finvoc); + (dbref player, dbref cause, char *arg1, char *cmd, bool until, char finvoc); +extern void do_waitpid(dbref, const char *, const char *, bool); enum queue_type { QUEUE_ALL, QUEUE_NORMAL, QUEUE_SUMMARY, QUEUE_QUICK }; extern void do_queue(dbref player, const char *what, enum queue_type flag); extern void do_halt1(dbref player, const char *arg1, const char *arg2); +void do_haltpid(dbref, const char *); extern void do_allhalt(dbref player); extern void do_allrestart(dbref player); extern void do_restart(void); @@ -41,7 +41,7 @@ extern void do_restart_com(dbref player, const char *arg1); /* Only QID_ACTIVE, QID_FALSE, and QID_FREEZE actually get thrown on a qid cell. * * other are just used to pass in function shit */ enum qid_flags {QID_ACTIVE, QID_KILL, QID_FREEZE, QID_CONT, QID_TIME, QID_QUERY_T, QID_FALSE}; -extern int do_signal_qid(dbref signalby, int qid, enum qid_flags qid_flags, int time); +extern int do_signal_qid(dbref signalby, uint32_t qid, enum qid_flags qid_flags, int time); /* From command.c */ enum hook_type { HOOK_BEFORE, HOOK_AFTER, HOOK_IGNORE, HOOK_OVERRIDE }; diff --git a/hdrs/getpgsiz.h b/hdrs/getpgsiz.h index e821cf6..5f85617 100644 --- a/hdrs/getpgsiz.h +++ b/hdrs/getpgsiz.h @@ -2,39 +2,17 @@ #define __GETPGSIZ_H #ifndef HAS_GETPAGESIZE -#ifdef PAGESIZE_VALUE -#define getpagesize() PAGESIZE_VALUE + +#ifdef HAS_SYSCONF +#define getpagesize() sysconf(_SC_PAGESIZE) +#elif defined(WIN32) +unsigned int getpagesize_win32(void); +#define getpagesize() getpagesize_win32() #else -#ifndef WIN32 -#ifdef I_SYS_PARAM -#include -#endif -#endif -#ifdef I_SYS_PAGE -#include +/* Guess. */ +#define getpagesize() 4096 #endif -#ifdef EXEC_PAGESIZE -#define getpagesize() EXEC_PAGESIZE -#else -#ifdef NBPG -#define getpagesize() NBPG * CLSIZE -#ifndef CLSIZE -#define CLSIZE 1 -#endif /* no CLSIZE */ -#else /* no NBPG */ -#ifdef NBPC -#define getpagesize() NBPC -#else /* no NBPC either? Bummer */ -#ifdef PAGESIZE -#define getpagesize() PAGESIZE -#else /* Sigh. Time for a total guess. */ -#define getpagesize() 1024 -#endif /* no PAGESIZE */ -#endif /* no NBPC */ -#endif /* no NBPG */ -#endif /* no EXEC_PAGESIZE */ -#endif /* no PAGESIZE_VALUE */ -#endif /* not HAS_GETPAGESIZE */ +#endif /* !HAS_GETPAGESIZE */ #endif /* __GETPGSIZ_H */ diff --git a/hdrs/htab.h b/hdrs/htab.h index 2fba985..526f5d7 100644 --- a/hdrs/htab.h +++ b/hdrs/htab.h @@ -3,60 +3,47 @@ #ifndef __HTAB_H #define __HTAB_H -#define SOME_KEY_LEN 10 - -#define HTAB_UPSCALE 4 -#define HTAB_DOWNSCALE 2 +typedef struct hashtable HASHTAB; -typedef struct hashentry HASHENT; -/** A hash table entry. - */ -struct hashentry { - struct hashentry *next; /**< Pointer to next entry */ - void *data; /**< Data for this entry */ - /* int extra_size; */ - char key[SOME_KEY_LEN]; /**< Key for this entry */ +/** Hash table bucket struct */ +struct hash_bucket { + const char *key; + void *data; }; -#define HASHENT_SIZE (sizeof(HASHENT)-SOME_KEY_LEN) - -typedef struct hashtable HASHTAB; /** A hash table. */ struct hashtable { - int hashsize; /**< Size of hash table */ - int mask; /**< Mask for entries in table */ + int hashsize; /**< Size of buckets array */ int entries; /**< Number of entries stored */ - HASHENT **buckets; /**< Pointer to pointer to entries */ - int last_hval; /**< State for hashfirst & hashnext. */ - HASHENT *last_entry; /**< State for hashfirst & hashnext. */ - int entry_size; /**< Size of each entry */ + int hashfunc_offset; /**< Which pair of hash functions to use */ + struct hash_bucket *buckets; /**< Buckets */ + int last_index; /**< State for hashfirst & hashnext. */ void (*free_data) (void *); /**< Function to call on data when deleting a entry. */ }; -#define get_hashmask(x) hash_getmask(x) -#define hashinit(x,y, z) hash_init(x,y, z, NULL) +typedef struct hash_bucket HASHENT; + +#define hashinit(tab, size) hash_init((tab), (size), NULL) #define hashfind(key,tab) hash_value(hash_find(tab,key)) -#define hashadd(key,data,tab) hash_add(tab,key,data, 0) -#define hashadds(key, data, tab, size) hash_add(tab, key, data, size) +#define hashadd(key,data,tab) hash_add(tab,key,data) #define hashdelete(key,tab) hash_delete(tab,hash_find(tab,key)) #define hashflush(tab, size) hash_flush(tab,size) #define hashfree(tab) hash_flush(tab, 0) -extern int hash_getmask(int *size); -extern void hash_init(HASHTAB *htab, int size, int data_size, void (*)(void *)); -extern HASHENT *hash_find(HASHTAB *htab, const char *key); -extern void *hash_value(HASHENT *entry); -extern char *hash_key(HASHENT *entry); -extern void hash_resize(HASHTAB *htab, int size); -extern int hash_add - (HASHTAB *htab, const char *key, void *hashdata, int extra_size); -extern void hash_delete(HASHTAB *htab, HASHENT *entry); -extern void hash_flush(HASHTAB *htab, int size); -extern void *hash_firstentry(HASHTAB *htab); -extern void *hash_nextentry(HASHTAB *htab); -extern char *hash_firstentry_key(HASHTAB *htab); -extern char *hash_nextentry_key(HASHTAB *htab); -extern void hash_stats_header(dbref player); -extern void hash_stats(dbref player, HASHTAB *htab, const char *hashname); +int hash_getmask(int *size); +void hash_init(HASHTAB *htab, int size, void (*)(void *)); +HASHENT *hash_find(HASHTAB *htab, const char *key); +#define hash_value(entry) (entry) ? (entry)->data : NULL +#define hash_key(entry) (entry) ? (entry)->key : NULL +bool hash_resize(HASHTAB *htab, int size); +bool hash_add(HASHTAB *htab, const char *key, void *hashdata); +void hash_delete(HASHTAB *htab, HASHENT *entry); +void hash_flush(HASHTAB *htab, int size); +void *hash_firstentry(HASHTAB *htab); +void *hash_nextentry(HASHTAB *htab); +const char *hash_firstentry_key(HASHTAB *htab); +const char *hash_nextentry_key(HASHTAB *htab); +void hash_stats_header(dbref player); +void hash_stats(dbref player, HASHTAB *htab, const char *hashname); #endif diff --git a/hdrs/ident.h b/hdrs/ident.h index e9d8f2f..2f68edd 100644 --- a/hdrs/ident.h +++ b/hdrs/ident.h @@ -57,7 +57,7 @@ extern "C" { struct sockaddr *raddr, socklen_t rlen, int *timeout); - void ident_free(IDENT *id); + void ident_free(IDENT * id); #ifdef __cplusplus } diff --git a/hdrs/intmap.h b/hdrs/intmap.h new file mode 100644 index 0000000..1b463e8 --- /dev/null +++ b/hdrs/intmap.h @@ -0,0 +1,28 @@ +/** + * \file intmap.h + * + * \brief Interface for maps with unsigned 32-bit integers as keys. + */ + +#ifndef INTMAP_H +#define INTMAP_H + +struct intmap; +typedef struct intmap intmap; + +typedef uint32_t im_key; /**< Integer map keys are 32-bit unsigned integers */ +/* typedef uint64_t im_key; */ + +intmap *im_new(void); +void im_destroy(intmap *); + +int64_t im_count(intmap *); + +bool im_insert(intmap *, im_key, void *); +void *im_find(intmap *, im_key); +bool im_exists(intmap *, im_key); +bool im_delete(intmap *, im_key); +void im_dump_graph(intmap *, const char *); +void im_stats_header(dbref); +void im_stats(dbref, intmap *, const char *); +#endif /* INTMAP_H */ diff --git a/hdrs/lock.h b/hdrs/lock.h index b055aee..af1c671 100644 --- a/hdrs/lock.h +++ b/hdrs/lock.h @@ -25,7 +25,7 @@ struct lock_list { lock_type type; /**< Type of lock */ boolexp key; /**< Lock value ("key") */ dbref creator; /**< Dbref of lock creator */ - int flags; /**< Lock flags */ + privbits flags; /**< Lock flags */ struct lock_list *next; /**< Pointer to next lock in object's list */ }; @@ -40,24 +40,26 @@ struct lock_msg_info { const char *failbase; /**< Base name of failure attribute */ }; -#define LF_VISUAL 0x1 /* Anyone can see this lock with lock()/elock() */ -#define LF_PRIVATE 0x2 /* This lock doesn't get inherited */ -#define LF_PRIVILEGE 0x4 /* Only privileged players can set/unset it */ -#define LF_LOCKED 0x8 /* Only the lock's owner can set/unset it */ -#define LF_NOCLONE 0x10 /* This lock isn't copied in @clone */ -#define LF_OX 0x20 /* This lock's success messages includes OX*. */ -#define LF_NOSUCCACTION 0x40 /* This lock doesn't have an @a-action for success. */ -#define LF_NOFAILACTION 0x80 /* This lock doesn't have an @a-action for failure */ -#define LF_OWNER 0x100 /* Lock can only be set/unset by object's owner */ +#define LF_VISUAL 0x1U /**< Anyone can see this lock with lock()/elock() */ +#define LF_PRIVATE 0x2U /**< This lock doesn't get inherited */ +#define LF_PRIVILEGE 0x4U /**< Only wizards can set/unset this lock */ +#define LF_LOCKED 0x8U /**< Only the lock's owner can set/unset it */ +#define LF_NOCLONE 0x10U /**< This lock isn't copied in @clone */ +#define LF_OX 0x20U /**< This lock's success messages includes OX*. */ +#define LF_NOSUCCACTION 0x40U /**< This lock doesn't have an @a-action for success. */ +#define LF_NOFAILACTION 0x80U /**< This lock doesn't have an @a-action for failure */ +#define LF_OWNER 0x100U /**< Lock can only be set/unset by object's owner */ +#define LF_DEFAULT 0x200U /**< Use default flags when setting lock */ -/* lock.c */ + /* lock.c */ boolexp getlock(dbref thing, lock_type type); boolexp getlock_noparent(dbref thing, lock_type type); lock_type match_lock(lock_type type); const lock_list *get_lockproto(lock_type type); -int add_lock(dbref player, dbref thing, lock_type type, boolexp key, int flags); +int add_lock(dbref player, dbref thing, lock_type type, boolexp key, + privbits flags); int add_lock_raw(dbref player, dbref thing, lock_type type, - boolexp key, int flags); + boolexp key, privbits flags); void free_locks(lock_list *ll); int eval_lock(dbref player, dbref thing, lock_type ltype); int eval_lock_with(dbref player, dbref thing, lock_type ltype, dbref env0, @@ -75,51 +77,44 @@ void list_locks(char *buff, char **bp, const char *name); const char *lock_flags(lock_list *ll); const char *lock_flags_long(lock_list *ll); void check_zone_lock(dbref player, dbref zone, int noisy); +void define_lock(lock_type name, privbits flags); #define L_FLAGS(lock) ((lock)->flags) #define L_CREATOR(lock) ((lock)->creator) #define L_TYPE(lock) ((lock)->type) #define L_KEY(lock) ((lock)->key) #define L_NEXT(lock) ((lock)->next) /* can p read/evaluate lock l on object x? */ -int lock_visual(dbref, lock_type); +bool lock_visual(dbref, lock_type); #define Can_Read_Lock(p,x,l) \ (CanSee(p, x) || controls(p,x) || ((Visual(x) || lock_visual(x, l)) && \ eval_lock(p,x,Examine_Lock))) /* The actual magic cookies. */ -extern const lock_type Basic_Lock; -extern const lock_type Enter_Lock; -extern const lock_type Use_Lock; -extern const lock_type Zone_Lock; -extern const lock_type Page_Lock; -extern const lock_type Tport_Lock; -extern const lock_type Speech_Lock; /* Who can speak aloud in me */ -extern const lock_type Listen_Lock; /* Who can trigger ^s/ahears on me */ -extern const lock_type Command_Lock; /* Who can use $commands on me */ -extern const lock_type Parent_Lock; /* Who can @parent to me */ -extern const lock_type Link_Lock; /* Who can @link to me */ -extern const lock_type Leave_Lock; /* Who can leave me */ -extern const lock_type Drop_Lock; /* Who can drop me */ -extern const lock_type Give_Lock; /* Who can give me */ -extern const lock_type Mail_Lock; /* Who can @mail me */ -extern const lock_type Follow_Lock; /* Who can follow me */ -extern const lock_type Examine_Lock; /* Who can examine visual me */ -extern const lock_type Chzone_Lock; /* Who can @chzone to this object? */ -extern const lock_type Forward_Lock; /* Who can @forwardlist to object? */ -extern const lock_type Control_Lock; /* Who can control this object? */ -extern const lock_type Dropto_Lock; /* Who follows the dropto of this room? */ -extern const lock_type Destroy_Lock; /* Who can @dest me if I'm dest_ok? */ -extern const lock_type Interact_Lock; -extern const lock_type MailForward_Lock; /* Who can forward mail to me */ -extern const lock_type Take_Lock; /* Who can take from the contents of this object? */ -/* channel locks */ -#ifdef NEWCHAT -extern const lock_type chan_speak_lock; -extern const lock_type chan_join_lock; -extern const lock_type chan_mod_lock; -extern const lock_type chan_see_lock; -extern const lock_type chan_hide_lock; -#endif +extern lock_type Basic_Lock; +extern lock_type Enter_Lock; +extern lock_type Use_Lock; +extern lock_type Zone_Lock; +extern lock_type Page_Lock; +extern lock_type Tport_Lock; +extern lock_type Speech_Lock; /* Who can speak aloud in me */ +extern lock_type Listen_Lock; /* Who can trigger ^s/ahears on me */ +extern lock_type Command_Lock; /* Who can use $commands on me */ +extern lock_type Parent_Lock; /* Who can @parent to me */ +extern lock_type Link_Lock; /* Who can @link to me */ +extern lock_type Leave_Lock; /* Who can leave me */ +extern lock_type Drop_Lock; /* Who can drop me */ +extern lock_type Give_Lock; /* Who can give me */ +extern lock_type Mail_Lock; /* Who can @mail me */ +extern lock_type Follow_Lock; /* Who can follow me */ +extern lock_type Examine_Lock; /* Who can examine visual me */ +extern lock_type Chzone_Lock; /* Who can @chzone to this object? */ +extern lock_type Forward_Lock; /* Who can @forwardlist to object? */ +extern lock_type Control_Lock; /* Who can control this object? */ +extern lock_type Dropto_Lock; /* Who follows the dropto of this room? */ +extern lock_type Destroy_Lock; /* Who can @dest me if I'm dest_ok? */ +extern lock_type Interact_Lock; +extern lock_type MailForward_Lock; /* Who can forward mail to me */ +extern lock_type Take_Lock; /* Who can take from the contents of this object? */ /* Declare new lock types here! */ diff --git a/hdrs/lookup.h b/hdrs/lookup.h new file mode 100644 index 0000000..ff6542a --- /dev/null +++ b/hdrs/lookup.h @@ -0,0 +1,60 @@ +/** + * \file lookup.h + * \brief Prototypes and data structures for talking with info_slave + * + * Must be #included after mysocket.h and ident.h to get appropriate + * types and constants. + * + * netmush and info_slave use UDP datagrams to talk to each + * other. Each datagram is one recv/send, with a max size of + * something like 8K (Less than that on OS X in practice). We're well under + * that. Using datagrams instead of streams vastly simplies the communication + * code. We should have done it years ago. + */ + +#ifndef LOOKUP_H +#define LOOKUP_H + +#include "copyrite.h" + +/** Datagram sent to info_slave from the mush */ +struct request_dgram { + int fd; /**< The socket descriptor, used as an id number */ + union sockaddr_u local; /**< The sockaddr struct for the local address */ + union sockaddr_u remote; /**< The sockaddr struct for the remote address */ + socklen_t llen; /**< Length of local address */ + socklen_t rlen; /**< Length of remote address */ + int use_ident; /**< True to do an ident lookup */ + int use_dns; /**< True to do hostname lookup */ + int timeout; /**< Timeout in seconds for lookups */ +}; + +#define IPADDR_LEN 128 +#define HOSTNAME_LEN 256 +#define IDENT_LEN 128 + +/** Datagram sent by info_slave back to the mush */ +struct response_dgram { + int fd; /**< The socket descriptor, used as an id number */ + char ipaddr[IPADDR_LEN]; /**< The ip address of the connection */ + char hostname[HOSTNAME_LEN]; /**< The resolved hostname of the connection */ + char ident[IDENT_LEN]; /**< The ident name for the connection */ + Port_t connected_to; /**< The port connected to. */ +}; + +extern pid_t info_slave_pid; +extern int info_slave; +extern time_t info_queue_time; +extern bool info_slave_halted; + +enum is_state { INFO_SLAVE_DOWN, INFO_SLAVE_READY, INFO_SLAVE_PENDING }; + +extern enum is_state info_slave_state; + +void init_info_slave(void); +void query_info_slave(int fd); +void update_pending_info_slaves(void); +void reap_info_slave(void); +void kill_info_slave(void); + +#endif /* LOOKUP_H */ diff --git a/hdrs/modules.h b/hdrs/modules.h index 5b1c30f..86687f4 100644 --- a/hdrs/modules.h +++ b/hdrs/modules.h @@ -26,12 +26,13 @@ int modules_shutdown(void); #define MODULE_CAF(mem,check) if(mem != NULL) \ mush_free(mem, check); /* Retrieve Module Function */ +/* This Macro can only be used for non-returning calls */ #define MODULE_FUNC(h, m, func, ...) \ - if((h = lt_dlsym(m, func))) { \ + if((h = (void (*)()) lt_dlsym(m, func))) { \ h(__VA_ARGS__); \ } #define MODULE_FUNC_NOARGS(h, m, func) \ - if((h = lt_dlsym(m, func))) { \ + if((h = (void (*)()) lt_dlsym(m, func))) { \ h(); \ } diff --git a/hdrs/mushdb.h b/hdrs/mushdb.h index a63e7c1..56ac553 100644 --- a/hdrs/mushdb.h +++ b/hdrs/mushdb.h @@ -1,4 +1,7 @@ -/* mushdb.h */ +/** \file mushdb.h + * + * \brief Macros for getting information about objects + */ #include "config.h" #include "copyrite.h" @@ -7,6 +10,7 @@ #define __DB_H /* Power macros */ +#include #include "flags.h" #define LastMod(x) (db[x].lastmod) @@ -87,7 +91,7 @@ #define Can_See_Flag(p,t,f) OOREF(p,TC_Can_See_Flag(p,t,f),TC_Can_See_Flag(ooref,t,f)) /* Can p locate x? */ -int unfindable(dbref); +bool unfindable(dbref); #define TC_Can_Locate(p,x) \ (controls(p,x) || nearby(p,x) || CanSee(p,x) \ || (command_check_byname(p, "@whereis") && (IsPlayer(x) && !Unfind(x) \ @@ -217,6 +221,10 @@ int unfindable(dbref); #define DBF_NEW_FLAGS 0x20000 #define DBF_DIVISIONS 0x40000 #define DBF_LABELS 0x100000 +#define DBF_SPIFFY_AF_ANSI 0x200000 + + +/* CobraMUSH Specific DBF Flags */ #define DBF_NEW_ATR_LOCK 0x200000 #define DBF_ATR_MODTIME 0x400000 diff --git a/hdrs/mushtype.h b/hdrs/mushtype.h index 6a49f96..8b6df5a 100644 --- a/hdrs/mushtype.h +++ b/hdrs/mushtype.h @@ -4,7 +4,8 @@ #ifdef HAS_OPENSSL #include #endif - +#include + /* Connect Flags */ /** Default connection, nothing special */ #define CONN_DEFAULT 0 @@ -38,16 +39,27 @@ #define MAX_SNOOPS 30 -/* Function number type */ +/** Math function floating-point number type */ typedef double NVAL; -/* Dbref type */ -typedef int dbref; +/* Math function integral type */ +typedef int32_t IVAL; + +/** Math function unsigned integral type */ +typedef uint32_t UIVAL; + +#define SIZEOF_IVAL 4 + +/** Dbref type */ + typedef int dbref; /** The type that stores the warning bitmask */ -typedef long int warn_type; +typedef uint32_t warn_type; + +/** Attribute/lock flag types */ +typedef uint32_t privbits; -/* special dbref's */ + /* special dbref's */ #define NOTHING (-1) /* null dbref */ #define AMBIGUOUS (-2) /* multiple possibilities, for matchers */ #define HOME (-3) /* virtual room, represents mover's home */ @@ -150,8 +162,8 @@ struct descriptor_data { unsigned char *raw_input; /**< Pointer to start of next raw input */ unsigned char *raw_input_at; /**< Pointer to position in raw input */ int (*input_handler)(DESC *, char *); /**< Pointer to input handler */ - long connected_at; /**< Time of connection */ - long last_time; /**< Time of last activity */ + time_t connected_at; /**< Time of connection */ + time_t last_time; /**< Time of last activity */ long idle_total; /**< Total Idle Secs Expended.. This / Idle_Times == Idle Average for session */ int unidle_times; /**< Amoutn of Times unidled from 10 seconds */ int quota; /**< Quota of commands allowed */ @@ -170,9 +182,6 @@ struct descriptor_data { #endif struct descriptor_data *next; /**< Next descriptor in linked list */ struct descriptor_data *prev; /**< Previous descriptor in linked list */ -#ifdef USE_MAILER - struct mail *mailp; /**< Pointer to start of player's mail chain */ -#endif int conn_flags; /**< Flags of connection (telnet status, etc.) */ unsigned long input_chars; /**< Characters received */ unsigned long output_chars; /**< Characters sent */ diff --git a/hdrs/mymalloc.h b/hdrs/mymalloc.h index 12a1fe9..9ca85a6 100644 --- a/hdrs/mymalloc.h +++ b/hdrs/mymalloc.h @@ -18,4 +18,33 @@ #include "csrimalloc.h" #endif +typedef struct slab slab; +slab *slab_create(const char *name, size_t item_size); +void slab_destroy(slab *); +void *slab_malloc(slab *sl, const void *hint); +void slab_free(slab *sl, void *obj); + +enum slab_options { + SLAB_ALLOC_FIRST_FIT, /**< When allocating without a hint (Or when a + hint page is full) , use the first page + found with room for the object. Default. Mutually exclusive with SLAB_ALLOC_BEST_FIT. */ + SLAB_ALLOC_BEST_FIT, /**< When allocating without a hint (Or when a + hint page is full), use the page with the + fewest free objects. Mutually exclusive with SLAB_ALLOC_FIRST_FIT. */ + + SLAB_ALWAYS_KEEP_A_PAGE, /**< If set to 1, do not delete an empty + page if it is the only page allocated for + that slab. Defaults to 0. */ + + SLAB_HINTLESS_THRESHOLD /**< The number of free objects that must + exist in a page for a hintless object to + be allocated from it. Defaults to + 1. Raise for cases where you'll have a + lot of allocations using hints and + deletions, to improve caching -- e.g., + attributes. */ +}; + +void slab_set_opt(slab *sl, enum slab_options opt, int val); + #endif /* _MYMALLOC_H */ diff --git a/hdrs/mypcre.h b/hdrs/mypcre.h new file mode 100644 index 0000000..bc62578 --- /dev/null +++ b/hdrs/mypcre.h @@ -0,0 +1,215 @@ +#ifndef _MYPCRE_H +#define _MYPCRE_H + +/************************************************* +* Perl-Compatible Regular Expressions * +*************************************************/ + +/* In its original form, this is the .in file that is transformed by +"configure" into pcre.h. + + Copyright (c) 1997-2005 University of Cambridge + +----------------------------------------------------------------------------- +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of the University of Cambridge nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +----------------------------------------------------------------------------- +*/ + +/* Modified a bit by Shawn Wagner for inclusion in PennMUSH. See + pcre.c for details. */ + + +#define PENN_MATCH_LIMIT 100000 +struct pcre_extra; +void set_match_limit(struct pcre_extra *); +struct pcre_extra *default_match_limit(void); + +#ifdef HAVE_PCRE +#include +#else + + +#define PCRE_MAJOR 6 +#define PCRE_MINOR 4 +#define PCRE_DATE 05-Sep-2005 + +#ifndef PCRE_DATA_SCOPE +# define PCRE_DATA_SCOPE extern +#endif + +/* Have to include stdlib.h in order to ensure that size_t is defined; +it is needed here for malloc. */ + +#include + +/* Allow for C++ users */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Options */ + +#define PCRE_CASELESS 0x00000001 +#define PCRE_MULTILINE 0x00000002 +#define PCRE_DOTALL 0x00000004 +#define PCRE_EXTENDED 0x00000008 +#define PCRE_ANCHORED 0x00000010 +#define PCRE_DOLLAR_ENDONLY 0x00000020 +#define PCRE_EXTRA 0x00000040 +#define PCRE_NOTBOL 0x00000080 +#define PCRE_NOTEOL 0x00000100 +#define PCRE_UNGREEDY 0x00000200 +#define PCRE_NOTEMPTY 0x00000400 +#define PCRE_UTF8 0x00000800 +#define PCRE_NO_AUTO_CAPTURE 0x00001000 +#define PCRE_NO_UTF8_CHECK 0x00002000 +#define PCRE_AUTO_CALLOUT 0x00004000 +#define PCRE_PARTIAL 0x00008000 +#define PCRE_DFA_SHORTEST 0x00010000 +#define PCRE_DFA_RESTART 0x00020000 +#define PCRE_FIRSTLINE 0x00040000 + + +/* Exec-time and get/set-time error codes */ + +#define PCRE_ERROR_NOMATCH (-1) +#define PCRE_ERROR_NULL (-2) +#define PCRE_ERROR_BADOPTION (-3) +#define PCRE_ERROR_BADMAGIC (-4) +#define PCRE_ERROR_UNKNOWN_NODE (-5) +#define PCRE_ERROR_NOMEMORY (-6) +#define PCRE_ERROR_NOSUBSTRING (-7) +#define PCRE_ERROR_MATCHLIMIT (-8) +#define PCRE_ERROR_CALLOUT (-9) /* Never used by PCRE itself */ +#define PCRE_ERROR_BADUTF8 (-10) +#define PCRE_ERROR_BADUTF8_OFFSET (-11) +#define PCRE_ERROR_PARTIAL (-12) +#define PCRE_ERROR_BADPARTIAL (-13) +#define PCRE_ERROR_INTERNAL (-14) +#define PCRE_ERROR_BADCOUNT (-15) +#define PCRE_ERROR_DFA_UITEM (-16) +#define PCRE_ERROR_DFA_UCOND (-17) +#define PCRE_ERROR_DFA_UMLIMIT (-18) +#define PCRE_ERROR_DFA_WSSIZE (-19) +#define PCRE_ERROR_DFA_RECURSE (-20) + +/* Request types for pcre_fullinfo() */ + +#define PCRE_INFO_OPTIONS 0 +#define PCRE_INFO_SIZE 1 +#define PCRE_INFO_CAPTURECOUNT 2 +#define PCRE_INFO_BACKREFMAX 3 +#define PCRE_INFO_FIRSTBYTE 4 +#define PCRE_INFO_FIRSTCHAR 4 /* For backwards compatibility */ +#define PCRE_INFO_FIRSTTABLE 5 +#define PCRE_INFO_LASTLITERAL 6 +#define PCRE_INFO_NAMEENTRYSIZE 7 +#define PCRE_INFO_NAMECOUNT 8 +#define PCRE_INFO_NAMETABLE 9 +#define PCRE_INFO_STUDYSIZE 10 +#define PCRE_INFO_DEFAULT_TABLES 11 + +/* Request types for pcre_config() */ + +#define PCRE_CONFIG_UTF8 0 +#define PCRE_CONFIG_NEWLINE 1 +#define PCRE_CONFIG_LINK_SIZE 2 +#define PCRE_CONFIG_POSIX_MALLOC_THRESHOLD 3 +#define PCRE_CONFIG_MATCH_LIMIT 4 + +/* Bit flags for the pcre_extra structure */ + +#define PCRE_EXTRA_STUDY_DATA 0x0001 +#define PCRE_EXTRA_MATCH_LIMIT 0x0002 +#define PCRE_EXTRA_CALLOUT_DATA 0x0004 +#define PCRE_EXTRA_TABLES 0x0008 + +/* Types */ + + struct real_pcre; /* declaration; the definition is private */ + typedef struct real_pcre pcre; + +/* The structure for passing additional data to pcre_exec(). This is defined in +such as way as to be extensible. */ + + typedef struct pcre_extra { + unsigned long int flags; /* Bits for which fields are set */ + void *study_data; /* Opaque data from pcre_study() */ + unsigned long int match_limit; /* Maximum number of calls to match() */ + void *callout_data; /* Data passed back in callouts */ + const unsigned char *tables; /* Pointer to character tables */ + } pcre_extra; + +/* The structure for passing out data via the pcre_callout_function. We use a +structure so that new fields can be added on the end in future versions, +without changing the API of the function, thereby allowing old clients to work +without modification. */ + + typedef struct pcre_callout_block { + int version; /* Identifies version of block */ + /* ------------------------ Version 0 ------------------------------- */ + int callout_number; /* Number compiled into pattern */ + int *offset_vector; /* The offset vector */ + const char *subject; /* The subject being matched */ + int subject_length; /* The length of the subject */ + int start_match; /* Offset to start of this match attempt */ + int current_position; /* Where we currently are in the subject */ + int capture_top; /* Max current capture */ + int capture_last; /* Most recently closed capture */ + void *callout_data; /* Data passed in with the call */ + /* ------------------- Added for Version 1 -------------------------- */ + int pattern_position; /* Offset to next item in the pattern */ + int next_item_length; /* Length of next item in the pattern */ + /* ------------------------------------------------------------------ */ + } pcre_callout_block; + + +/* Exported PCRE functions */ + + extern pcre *pcre_compile(const char *, int, const char **, + int *, const unsigned char *); + extern int pcre_copy_substring(const char *, int *, int, int, char *, int); + int pcre_get_substring(const char *, int *, int, int, const char **); + extern int pcre_exec(const pcre *, const pcre_extra *, + const char *, int, int, int, int *, int); + extern const unsigned char *pcre_maketables(void); + extern pcre_extra *pcre_study(const pcre *, int, const char **); + extern int pcre_fullinfo(const pcre * argument_re, + const pcre_extra * extra_data, int what, + void *where); + extern int pcre_get_stringnumber(const pcre * code, const char *stringname); + extern int + pcre_copy_named_substring(const pcre * code, const char *subject, + int *ovector, int stringcount, + const char *stringname, char *buffer, int size); + +#ifdef __cplusplus +} /* extern "C" */ +#endif +#endif /* !HAVE_PCRE */ +#endif /* End of pcre.h */ diff --git a/hdrs/mysocket.h b/hdrs/mysocket.h index e412efc..2cfd2e1 100644 --- a/hdrs/mysocket.h +++ b/hdrs/mysocket.h @@ -24,7 +24,6 @@ #define ETIMEDOUT WSAETIMEDOUT #define EAFNOSUPPORT WSAEAFNOSUPPORT #define ENOSPC 28 -#define snprintf _snprintf #define MAXHOSTNAMELEN 32 #pragma comment( lib, "wsock32.lib") #pragma comment( lib, "winmm.lib") @@ -38,10 +37,6 @@ #define MAXSOCKADDR 128 #endif -#ifndef HAS_SOCKLEN_T -typedef unsigned int socklen_t; -#endif - /** Information about a host. */ struct hostname_info { @@ -64,14 +59,16 @@ struct hostname_info *ip_convert(struct sockaddr *host, int len); /* Open a socket for listening */ int make_socket - (Port_t port, union sockaddr_u *addr, socklen_t *len, const char *host); -/* Connect somewhere */ -int make_socket_conn(const char *host, struct sockaddr *myiterface, - socklen_t myilen, Port_t port, int *timeout); + (Port_t port, int socktype, union sockaddr_u *addr, socklen_t * len, + const char *host); +/* Connect somewhere using TCP */ +int make_socket_conn(const char *host, int socktype, + struct sockaddr *myiterface, socklen_t myilen, Port_t port, + bool nonb); +int wait_for_connect(int, int); void make_nonblocking(int s); +void make_blocking(int s); void set_keepalive(int s); -int connect_nonb - (int sockfd, const struct sockaddr *saptr, socklen_t salen, int *nsec); /* Win32 uses closesocket() to close a socket, and so will we */ #ifndef WIN32 #define closesocket(s) close(s) diff --git a/hdrs/parse.h b/hdrs/parse.h index d5194ca..c149663 100644 --- a/hdrs/parse.h +++ b/hdrs/parse.h @@ -19,9 +19,6 @@ #include "confmagic.h" -/* This is the type to be used for numbers which may be non-integral. */ -#define HUGE_NVAL HUGE_DOUBLE - /* These are some common error messages. */ extern char e_int[]; /* #-1 ARGUMENT MUST BE INTEGER */ extern char e_ints[]; /* #-1 ARGUMENTS MUST BE INTEGERS */ @@ -40,13 +37,22 @@ extern char e_range[]; /* #-1 OUT OF RANGE */ * data of the appropriate types. */ -extern int parse_boolean(char const *str); -extern dbref parse_dbref(char const *str); -extern dbref qparse_dbref(char const *str); -extern dbref parse_objid(char const *str); +bool parse_boolean(char const *str); +dbref parse_dbref(char const *str); +dbref qparse_dbref(char const *str); +dbref parse_objid(char const *str); + +int parse_int(const char *, char **, int); +unsigned int parse_uint(const char *, char **, int); +#define parse_integer(s) parse_int(s, NULL, 10) +#define parse_uinteger(s) parse_uint(s, NULL, 10) + +int32_t parse_int32(const char *, char **, int); +uint32_t parse_uint32(const char *, char **, int); -#define parse_integer(str) strtol(str, NULL, 10) -#define parse_uinteger(str) strtoul(str, NULL, 10) +/* TO-DO: Add parse_X/is_X/unparse_X and maybe safe_X as needed for + * long, unsigned long, size_t, intmax_t, int32_t, uint32_t, int64_t + * uint64_t, time_t */ #define parse_number(str) strtod(str, NULL) @@ -69,19 +75,19 @@ char *unparse_types(int type); /* The following routines all take strings as arguments, and return * true if the string is a valid representation of the appropriate type. */ -int is_dbref(char const *str); -int is_objid(char const *str); +bool is_dbref(char const *str); +bool is_objid(char const *str); -int is_integer(char const *str); -int is_uinteger(char const *str); -int is_boolean(char const *str); +bool is_integer(char const *str); +bool is_uinteger(char const *str); +bool is_boolean(char const *str); /* Split a sep-delimited string into individual elements */ extern int list2arr(char *r[], int max, char *list, char sep); /* split up a sep-delimietd string into individual elements and acknowledge that the seperate character may be escaepd out */ extern int elist2arr(char *r[], int max, char *list, char sep); /* The reverse */ -extern void arr2list(char *r[], int max, char *list, char **lp, char *sep); +extern void arr2list(char *r[], int max, char *list, char **lp, const char *sep); /* Split a sep-delimited string into individual elements. * Uses mush_strdup, so freearr() is required on all * list2arr_ansi()'d arrays (r) */ @@ -152,7 +158,7 @@ typedef struct fun FUN; int process_expression(char *buff, char **bp, char const **str, dbref executor, dbref caller, dbref enactor, - int eflags, int tflags, PE_Info * pe_info); + int eflags, int tflags, PE_Info *pe_info); /* buff is a pointer to a BUFFER_LEN string to contain the expression * result. *bp is the point in buff at which the result should be written. @@ -184,6 +190,8 @@ int process_expression(char *buff, char **bp, char const **str, #define PE_LITERAL 0x00000100 #define PE_DOLLAR 0x00000200 #define PE_DEBUG 0x00000400 +#define PE_BUILTINONLY 0x00000800 +#define PE_USERFN 0x00001000 #define PE_DEFAULT (PE_COMPRESS_SPACES | PE_STRIP_BRACES | \ PE_DOLLAR | PE_EVALUATE | PE_FUNCTION_CHECK) @@ -217,6 +225,13 @@ int process_expression(char *buff, char **bp, char const **str, * PE_UDEFAULT is PE_DEFAULT without PE_DOLLAR, intended for use in * calling attributes (via u(), mix, step, etc) * + * PE_DEBUG means we're debugging this evaluation. + * + * PE_BUILTINONLY means that we should only evaluate built-in functions, + * not @functions. It's used for the fn() function. + * + * PE_USERFN means we're evaluating within an @function + * * * tflags consists of one or more of the following termination flags: */ diff --git a/hdrs/pcre.h b/hdrs/pcre.h index af1ddbe..e69de29 100644 --- a/hdrs/pcre.h +++ b/hdrs/pcre.h @@ -1,203 +0,0 @@ -/************************************************* -* Perl-Compatible Regular Expressions * -*************************************************/ - -/* In its original form, this is the .in file that is transformed by -"configure" into pcre.h. - - Copyright (c) 1997-2005 University of Cambridge - ------------------------------------------------------------------------------ -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - * Neither the name of the University of Cambridge nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. ------------------------------------------------------------------------------ -*/ - -/* Modified a bit by Shawn Wagner for inclusion in PennMUSH. See - pcre.c for details. */ - -#ifndef _PCRE_H -#define _PCRE_H - -#define PCRE_MAJOR 6 -#define PCRE_MINOR 4 -#define PCRE_DATE 05-Sep-2005 - -#ifndef PCRE_DATA_SCOPE -# define PCRE_DATA_SCOPE extern -#endif - -/* Have to include stdlib.h in order to ensure that size_t is defined; -it is needed here for malloc. */ - -#include - -/* Allow for C++ users */ - -#ifdef __cplusplus -extern "C" { -#endif - -/* Options */ - -#define PCRE_CASELESS 0x00000001 -#define PCRE_MULTILINE 0x00000002 -#define PCRE_DOTALL 0x00000004 -#define PCRE_EXTENDED 0x00000008 -#define PCRE_ANCHORED 0x00000010 -#define PCRE_DOLLAR_ENDONLY 0x00000020 -#define PCRE_EXTRA 0x00000040 -#define PCRE_NOTBOL 0x00000080 -#define PCRE_NOTEOL 0x00000100 -#define PCRE_UNGREEDY 0x00000200 -#define PCRE_NOTEMPTY 0x00000400 -#define PCRE_UTF8 0x00000800 -#define PCRE_NO_AUTO_CAPTURE 0x00001000 -#define PCRE_NO_UTF8_CHECK 0x00002000 -#define PCRE_AUTO_CALLOUT 0x00004000 -#define PCRE_PARTIAL 0x00008000 -#define PCRE_DFA_SHORTEST 0x00010000 -#define PCRE_DFA_RESTART 0x00020000 -#define PCRE_FIRSTLINE 0x00040000 - - -/* Exec-time and get/set-time error codes */ - -#define PCRE_ERROR_NOMATCH (-1) -#define PCRE_ERROR_NULL (-2) -#define PCRE_ERROR_BADOPTION (-3) -#define PCRE_ERROR_BADMAGIC (-4) -#define PCRE_ERROR_UNKNOWN_NODE (-5) -#define PCRE_ERROR_NOMEMORY (-6) -#define PCRE_ERROR_NOSUBSTRING (-7) -#define PCRE_ERROR_MATCHLIMIT (-8) -#define PCRE_ERROR_CALLOUT (-9) /* Never used by PCRE itself */ -#define PCRE_ERROR_BADUTF8 (-10) -#define PCRE_ERROR_BADUTF8_OFFSET (-11) -#define PCRE_ERROR_PARTIAL (-12) -#define PCRE_ERROR_BADPARTIAL (-13) -#define PCRE_ERROR_INTERNAL (-14) -#define PCRE_ERROR_BADCOUNT (-15) -#define PCRE_ERROR_DFA_UITEM (-16) -#define PCRE_ERROR_DFA_UCOND (-17) -#define PCRE_ERROR_DFA_UMLIMIT (-18) -#define PCRE_ERROR_DFA_WSSIZE (-19) -#define PCRE_ERROR_DFA_RECURSE (-20) - -/* Request types for pcre_fullinfo() */ - -#define PCRE_INFO_OPTIONS 0 -#define PCRE_INFO_SIZE 1 -#define PCRE_INFO_CAPTURECOUNT 2 -#define PCRE_INFO_BACKREFMAX 3 -#define PCRE_INFO_FIRSTBYTE 4 -#define PCRE_INFO_FIRSTCHAR 4 /* For backwards compatibility */ -#define PCRE_INFO_FIRSTTABLE 5 -#define PCRE_INFO_LASTLITERAL 6 -#define PCRE_INFO_NAMEENTRYSIZE 7 -#define PCRE_INFO_NAMECOUNT 8 -#define PCRE_INFO_NAMETABLE 9 -#define PCRE_INFO_STUDYSIZE 10 -#define PCRE_INFO_DEFAULT_TABLES 11 - -/* Request types for pcre_config() */ - -#define PCRE_CONFIG_UTF8 0 -#define PCRE_CONFIG_NEWLINE 1 -#define PCRE_CONFIG_LINK_SIZE 2 -#define PCRE_CONFIG_POSIX_MALLOC_THRESHOLD 3 -#define PCRE_CONFIG_MATCH_LIMIT 4 - -/* Bit flags for the pcre_extra structure */ - -#define PCRE_EXTRA_STUDY_DATA 0x0001 -#define PCRE_EXTRA_MATCH_LIMIT 0x0002 -#define PCRE_EXTRA_CALLOUT_DATA 0x0004 -#define PCRE_EXTRA_TABLES 0x0008 - -/* Types */ - - struct real_pcre; /* declaration; the definition is private */ - typedef struct real_pcre pcre; - -/* The structure for passing additional data to pcre_exec(). This is defined in -such as way as to be extensible. */ - - typedef struct pcre_extra { - unsigned long int flags; /* Bits for which fields are set */ - void *study_data; /* Opaque data from pcre_study() */ - unsigned long int match_limit; /* Maximum number of calls to match() */ - void *callout_data; /* Data passed back in callouts */ - const unsigned char *tables; /* Pointer to character tables */ - } pcre_extra; - -/* The structure for passing out data via the pcre_callout_function. We use a -structure so that new fields can be added on the end in future versions, -without changing the API of the function, thereby allowing old clients to work -without modification. */ - - typedef struct pcre_callout_block { - int version; /* Identifies version of block */ - /* ------------------------ Version 0 ------------------------------- */ - int callout_number; /* Number compiled into pattern */ - int *offset_vector; /* The offset vector */ - const char *subject; /* The subject being matched */ - int subject_length; /* The length of the subject */ - int start_match; /* Offset to start of this match attempt */ - int current_position; /* Where we currently are in the subject */ - int capture_top; /* Max current capture */ - int capture_last; /* Most recently closed capture */ - void *callout_data; /* Data passed in with the call */ - /* ------------------- Added for Version 1 -------------------------- */ - int pattern_position; /* Offset to next item in the pattern */ - int next_item_length; /* Length of next item in the pattern */ - /* ------------------------------------------------------------------ */ - } pcre_callout_block; - - -/* Exported PCRE functions */ - - extern pcre *pcre_compile(const char *, int, const char **, - int *, const unsigned char *); - extern int pcre_copy_substring(const char *, int *, int, int, char *, int); - int pcre_get_substring(const char *, int *, int, int, const char **); - extern int pcre_exec(const pcre *, const pcre_extra *, - const char *, int, int, int, int *, int); - extern const unsigned char *pcre_maketables(void); - extern pcre_extra *pcre_study(const pcre *, int, const char **); - extern int pcre_fullinfo(const pcre * argument_re, - const pcre_extra * extra_data, int what, - void *where); - extern int pcre_get_stringnumber(const pcre * code, const char *stringname); - extern int - pcre_copy_named_substring(const pcre * code, const char *subject, - int *ovector, int stringcount, - const char *stringname, char *buffer, int size); - -#ifdef __cplusplus -} /* extern "C" */ -#endif -#endif /* End of pcre.h */ diff --git a/hdrs/privtab.h b/hdrs/privtab.h index aa31a86..e1dd1cf 100644 --- a/hdrs/privtab.h +++ b/hdrs/privtab.h @@ -8,8 +8,8 @@ #include "config.h" #include "confmagic.h" - typedef struct priv_info PRIV; + /** Privileges. * This structure represents a privilege and its associated data. * Privileges tables are used to provide a unified way to parse @@ -18,8 +18,8 @@ typedef struct priv_info PRIV; struct priv_info { const char *name; /**< Name of the privilege */ char letter; /**< One-letter abbreviation */ - long int bits_to_set; /**< Bitflags required to set this privilege */ - long int bits_to_show; /**< Bitflags required to see this privilege */ + privbits bits_to_set; /**< Bitflags required to set this privilege */ + privbits bits_to_show; /**< Bitflags required to see this privilege */ }; #define PrivName(x) ((x)->name) @@ -27,12 +27,12 @@ struct priv_info { #define PrivSetBits(x) ((x)->bits_to_set) #define PrivShowBits(x) ((x)->bits_to_show) -extern int string_to_privs(PRIV *table, const char *str, long int origprivs); -extern int list_to_privs(PRIV *table, const char *str, long int origprivs); -extern int string_to_privsets(PRIV *table, const char *str, int *setprivs, - int *clrprivs); -extern int letter_to_privs(PRIV *table, const char *str, long int origprivs); -extern const char *privs_to_string(PRIV *table, int privs); -extern const char *privs_to_letters(PRIV *table, int privs); +privbits string_to_privs(PRIV *table, const char *str, privbits origprivs); +privbits list_to_privs(PRIV *table, const char *str, privbits origprivs); +int string_to_privsets(PRIV *table, const char *str, privbits *setprivs, + privbits *clrprivs); +privbits letter_to_privs(PRIV *table, const char *str, privbits origprivs); +extern const char *privs_to_string(PRIV *table, privbits privs); +extern const char *privs_to_letters(PRIV *table, privbits privs); #endif /* __PRIVTAB_H */ diff --git a/hdrs/ptab.h b/hdrs/ptab.h index 5540986..75f965f 100644 --- a/hdrs/ptab.h +++ b/hdrs/ptab.h @@ -9,10 +9,10 @@ struct ptab_entry; * data is looked up by the best matching prefix of the given key. */ typedef struct ptab { - int state; /**< Internal table state */ - int len; /**< Table size */ - int maxlen; /**< Maximum table size */ - int current; /**< Internal table state */ + bool state; /**< Internal table state */ + size_t len; /**< Table size */ + size_t maxlen; /**< Maximum table size */ + size_t current; /**< Internal table state */ struct ptab_entry **tab; /**< Pointer to array of entries */ } PTAB; @@ -25,6 +25,7 @@ void ptab_delete(PTAB *, const char *); void ptab_start_inserts(PTAB *); void ptab_end_inserts(PTAB *); void ptab_insert(PTAB *, const char *, void *); +void ptab_insert_one(PTAB *, const char *, void *); void ptab_stats_header(dbref); void ptab_stats(dbref, PTAB *, const char *); void *ptab_firstentry_new(PTAB *, char *key); diff --git a/hdrs/pueblo.h b/hdrs/pueblo.h index 1853b6d..0625ba2 100644 --- a/hdrs/pueblo.h +++ b/hdrs/pueblo.h @@ -20,35 +20,12 @@ #define PEND \ *pp=0; -#define notify_nopenter_by(t,a,b) notify_anything(t, na_one, &(a), NULL, NA_NOPENTER, b) -#define notify_nopenter(a,b) notify_nopenter_by(GOD, a, b) -#define notify_noenter_by(t,a,b) notify_anything(t, na_one, &(a), NULL, NA_NOENTER, b) -#define notify_noenter(a,b) notify_noenter_by(GOD, a, b) - #define tag_wrap(a,b,c) safe_tag_wrap(a,b,c,pbuff,&pp,NOTHING) #define tag(a) safe_tag(a,pbuff,&pp) #define tag_cancel(a) safe_tag_cancel(a,pbuff,&pp) -#define notify_pueblo(a,b) notify_anything(GOD, na_one, &(a), NULL, NA_PONLY | NA_NOPENTER | NA_NOLISTEN, b) - -int safe_tag(char const *a_tag, char *buf, char **bp); -int safe_tag_cancel(char const *a_tag, char *buf, char **bp); -int safe_tag_wrap(char const *a_tag, char const *params, - char const *data, char *buf, char **bp, dbref player); - /* Please STAY SANE when modifying. * Making this something like 'x' and 'y' is a BAD IDEA */ -#define TAG_START '\02' -#define TAG_END '\03' - -/* Start & Cancel raw mud text */ -/* Use this for when we go into pueblo displaying shit */ -#define PUEBLO_CMT(buf,bp) safe_str("", buf, bp); \ - safe_str("", buf, bp); - -/* Use this when we go back to normal shit */ -#define PUEBLO_SMT(buf, bp) safe_str("", buf, bp); - #endif diff --git a/hdrs/shs.h b/hdrs/shs.h index ca5027f..a13e4c0 100644 --- a/hdrs/shs.h +++ b/hdrs/shs.h @@ -2,7 +2,7 @@ #define _SHS_H #include "config.h" -#ifdef I_STDINT +#ifdef HAVE_STDINT #include #endif #include "confmagic.h" @@ -40,6 +40,6 @@ typedef struct { } SHS_INFO; void shsInit(SHS_INFO *shsInfo); -void shsUpdate(SHS_INFO *shsInfo, const BYTE * buffer, int count); +void shsUpdate(SHS_INFO *shsInfo, const BYTE *buffer, int count); void shsFinal(SHS_INFO *shsInfo); #endif diff --git a/hdrs/sort.h b/hdrs/sort.h new file mode 100644 index 0000000..2603d8f --- /dev/null +++ b/hdrs/sort.h @@ -0,0 +1,30 @@ +#ifndef __PENNSORT_H +#define __PENNSORT_H +#include "copyrite.h" + +/* Sort and comparision functions */ + +#define MAX_SORTSIZE (BUFFER_LEN / 2) /**< Maximum number of elements to sort */ + +char *autodetect_list(char **ptrs, int nptrs); +char *get_list_type(char *args[], int nargs, int type_pos, char *ptrs[], + int nptrs); +char *get_list_type_noauto(char *args[], int nargs, int type_pos); +int gencomp(dbref player, char *a, char *b, char *sort_type); +void do_gensort(dbref player, char *keys[], char *strs[], int n, + char *sort_type); +/** Type definition for a qsort comparison function */ +typedef int (*comp_func) (const void *, const void *); +void sane_qsort(void **array, int left, int right, comp_func compare); + + +/* Comparison functions for qsort() and other routines. */ +int int_comp(const void *s1, const void *s2); +int nval_comp(const void *s1, const void *s2); +int uint_comp(const void *s1, const void *s2); +int str_comp(const void *s1, const void *s2); +int stri_comp(const void *s1, const void *s2); +int dbref_comp(const void *s1, const void *s2); +int u_comp(const void *s1, const void *s2); /* For sortby() */ + +#endif /* __PENNSORT_H */ diff --git a/hdrs/strtree.h b/hdrs/strtree.h index 67c5845..e5363ce 100644 --- a/hdrs/strtree.h +++ b/hdrs/strtree.h @@ -36,6 +36,8 @@ char const *st_insert_perm(char const *s, StrTree *root); char const *st_find(char const *s, StrTree *root); void st_delete(char const *s, StrTree *root); void st_print(StrTree *root); +typedef void (*STFunc) (const char *, int, void *); +void st_walk(StrTree *, STFunc, void *); void st_flush(StrTree *root); extern long st_count; diff --git a/hdrs/wait.h b/hdrs/wait.h new file mode 100644 index 0000000..8dd407c --- /dev/null +++ b/hdrs/wait.h @@ -0,0 +1,42 @@ +/** + * \file wait.h + * + * \brief Process and process group control functions. + * + * Must be #included after config.h, and + */ + +#ifndef WAIT_H +#define WAIT_H + +#ifdef I_SYS_TYPES +#include +#endif +#ifdef HAVE_SYS_WAIT_H +#include +#endif + +/* What does wait*() return? */ +#ifdef HAS_WAITPID +typedef int WAIT_TYPE; +#else /* Use wait3 */ +#ifdef UNION_WAIT +typedef union wait WAIT_TYPE; +#else +typedef int WAIT_TYPE; +#endif +#endif + +/* Exit status of child processes */ +pid_t mush_wait(pid_t child, WAIT_TYPE *stat, int flags); + + +/* process groups and sessions */ +int set_process_group(pid_t, pid_t); +int new_process_group(void); +int new_process_session(void); + +/* Priorities */ +int lower_priority_by(pid_t, int); + +#endif /* WAIT_H */ diff --git a/hints/README b/hints/README new file mode 100644 index 0000000..727c0bd --- /dev/null +++ b/hints/README @@ -0,0 +1,16 @@ +The files in this directory contains additional information about +configuring PennMUSH on various operating systems. If there isn't +one for your OS, and you need to pass special options and/or set +the CPPFLAGS and LDFLAGS environment variables to add directories +to the search patch for libraries (Or if you had to do something +beyond what's in the provided hint file), please file a report at +http://dev.pennmush.org telling us what you had to do so the hints +can be added to the next release. + +For Windows hints and directions see the win32 directory. There are +instructions there for Microsoft compilers, cygwin, and mingw. + +The OS.txt files are the current ones. OS.sh files are hints from the +old configure system that we haven't updated yet. Please file a bug +report at the URL above if you have access to one of those systems and +are willing to help update hints for it. diff --git a/hints/cygwin.txt b/hints/cygwin.txt new file mode 100644 index 0000000..09d9dd3 --- /dev/null +++ b/hints/cygwin.txt @@ -0,0 +1 @@ +See win32/README.cygwin diff --git a/hints/darwin-fink.sh b/hints/darwin-fink.sh deleted file mode 100644 index bf3a742..0000000 --- a/hints/darwin-fink.sh +++ /dev/null @@ -1,7 +0,0 @@ -usenm="n" -cdecl='' -so='dylib' -osname='darwin' -loclibpth='/sw/lib' -ccflags='-I/sw/include' - diff --git a/hints/darwin.sh b/hints/darwin.sh deleted file mode 100644 index 0a9dffc..0000000 --- a/hints/darwin.sh +++ /dev/null @@ -1,3 +0,0 @@ -usenm="n" -cdecl='' - diff --git a/hints/freebsd.sh b/hints/freebsd.sh deleted file mode 100644 index ed7a3b8..0000000 --- a/hints/freebsd.sh +++ /dev/null @@ -1,6 +0,0 @@ -usenm=false -i_malloc='undef' -i_values='undef' -ccflags='-D_POSIX_C_SOURCE=2 -D__XSI_VISIBLE=1000 -D__BSD_VISIBLE -I/usr/local/include' -d_attribut=true -d_force_ipv4='define' diff --git a/hints/freebsd.txt b/hints/freebsd.txt new file mode 100644 index 0000000..52691e3 --- /dev/null +++ b/hints/freebsd.txt @@ -0,0 +1,8 @@ +Penn will compile and run out of the box on FreeBSD, with the caveats +below: + +* If you're using an IPv6-enabled install and 'sysctl + net.inet6.ip6.v6only' prints out 1, you'll have to get a sysadmin to + change it to 0 or run configure with --disable-ipv6 to allow IPv4 + connections. + diff --git a/hints/linux.txt b/hints/linux.txt new file mode 100644 index 0000000..a0e4b30 --- /dev/null +++ b/hints/linux.txt @@ -0,0 +1,6 @@ +No special configure options are needed for most linux +distributions. Exceptions are listed below: + + +* SuSE 9.X reportedly needs CFLAGS=-D__USE_POSIX + diff --git a/hints/linux_2.sh b/hints/linux_2.sh deleted file mode 100644 index ae6bc95..0000000 --- a/hints/linux_2.sh +++ /dev/null @@ -1,14 +0,0 @@ -nm_opt='-B' - -# sometimes mysql might be found in an actual mysql -# subdirectory in the library path.. We'll need to -# check for that - -if [ -d /usr/lib/mysql ]; then - ldflags='-L/usr/lib/mysql' - elif [ -d /usr/local/lib/mysql ]; then - ldflags='-L/usr/local/lib/mysql' -fi - - -echo "I suggest using sysmalloc when you edit options.h." diff --git a/hints/mac_os_x.txt b/hints/mac_os_x.txt new file mode 100644 index 0000000..4257303 --- /dev/null +++ b/hints/mac_os_x.txt @@ -0,0 +1,36 @@ +With the Xcode Developer Tools installed, configuring and building +just works. OS X includes OpenSSL and Sqlite3. MySQL and gettext-style +message translation isn't bundled with OS X, and must be installed +seperately. The fink package manager is recommended. It can be +downloaded at http://fink.sourceforge.net/ + +Once fink is installed, use the 'Fink Commander' application to +install packages, or, from the command line as an administrator, 'sudo +fink install PACKAGE'. + +The important packages for Penn: + +mysql15-dev : MySQL +postgresql82-dev : Postgresql +libgettext3-dev : Message translation. + +Answer yes when if asked if you want to install additional packages +that they depend on. + +fink installs packages in the /sw tree, which configure does not +normally check. Run it like so for message translation: + +% CPPFLAGS=-I/sw/include LDFLAGS=-L/sw/lib ./configure + +The database servers will be detected as long as /sw/bin is your path, +which, if you followed the installation istructions for fink, +will. Otherwise, run configure as: + +% ./configure --with-mysql=/sw/bin/mysql_config +or +% ./configure --with-postgresql=/sw/bin/pgconfig + +Misc. Stuff: + +On PowerPC Macs, consider adding -mdynamic-no-pic to CFLAGS. + diff --git a/hints/mingw32.sh b/hints/mingw32.sh deleted file mode 100644 index ede5bc2..0000000 --- a/hints/mingw32.sh +++ /dev/null @@ -1,4 +0,0 @@ -cc='gcc' -usenm='n' -libs='-lwsock32' -osname='mingw32' diff --git a/hints/mingw32.txt b/hints/mingw32.txt new file mode 100644 index 0000000..e03b663 --- /dev/null +++ b/hints/mingw32.txt @@ -0,0 +1 @@ +See win32/README.mingw diff --git a/hints/netbsd.txt b/hints/netbsd.txt new file mode 100644 index 0000000..64cb1d9 --- /dev/null +++ b/hints/netbsd.txt @@ -0,0 +1,17 @@ +Penn will compile and run out of the box on NetBSD, including OpenSSL +support, with the caveats below. + +* Mysql and Postgres should be detected if their packages have been + installed through pkgsrc or pkg_add and /usr/pkg/bin is in your + path. If you have the sqlite3 package installed and want to use it, + you need to tell configure to look in the /usr/pkg hierarchy for it: + + % CPPFLAGS=-I/usr/pkg/include LDFLAGS=-L/usr/pkg/lib ./configure + +* If you're using an IPv6-enabled install and 'sysctl + net.inet6.ip6.v6only' prints out 1, you'll have to get a sysadmin to + change it to 0 or run configure with --disable-ipv6 to allow IPv4 + connections. + + + diff --git a/hints/next.sh b/hints/next.sh deleted file mode 100644 index 560be4b..0000000 --- a/hints/next.sh +++ /dev/null @@ -1,5 +0,0 @@ -ccflags="-W -Wreturn-type -Wunused -Wswitch -Wshadow -Wwrite-strings" -echo -echo "NeXT note: You may have to use the native malloc rather than" -echo "smalloc.c or gmalloc.c" -echo diff --git a/hints/openbsd.sh b/hints/openbsd.sh deleted file mode 100644 index e6717c5..0000000 --- a/hints/openbsd.sh +++ /dev/null @@ -1,4 +0,0 @@ -usenm=false -inclwanted='/usr/local/include' -i_malloc='undef' -d_force_ipv4='define' diff --git a/hints/openbsd.txt b/hints/openbsd.txt new file mode 100644 index 0000000..1ef38b4 --- /dev/null +++ b/hints/openbsd.txt @@ -0,0 +1,8 @@ +Penn will compile and run out of the box on OpenBSD, with the caveats +below: + +* OpenBSD (4.2, probably other releases as well) will not forward IPv4 + connection to a listening IPv6 port by default, and the sysctl + invocation that should change this fails with an 'Operation not + supported' error. Pass --disable-ipv6 to configure. + diff --git a/hints/os2.sh b/hints/os2.sh deleted file mode 100644 index ad624af..0000000 --- a/hints/os2.sh +++ /dev/null @@ -1,6 +0,0 @@ -# Hints for OS/2, based on Sylvia's reports of the few config.h -# tweaks she's had to do -d_random='define' -d_lrand48='define' -d_gettblsz='define' -tablesize='ulimit(4,0)' diff --git a/hints/ultrix.sh b/hints/ultrix.sh deleted file mode 100644 index 0480346..0000000 --- a/hints/ultrix.sh +++ /dev/null @@ -1 +0,0 @@ -ccflags="-DOLD_ANSI" diff --git a/hints/win32-gcc.sh b/hints/win32-gcc.sh deleted file mode 100644 index 3b2a631..0000000 --- a/hints/win32-gcc.sh +++ /dev/null @@ -1,7 +0,0 @@ -# Hints for win32 with gcc -cc='gcc' -ccflags='-DWIN32' -usenm='n' -h_fcntl='false' -d_ipv6='undef' -d_setlocale='undef' diff --git a/hints/windows.txt b/hints/windows.txt new file mode 100644 index 0000000..827e2ae --- /dev/null +++ b/hints/windows.txt @@ -0,0 +1,6 @@ +See the readme files in win32/ + +README.txt for MSVC compilers. +README.cygwin for Cygwin. +README.mingw for MSys. + diff --git a/install-sh b/install-sh new file mode 100644 index 0000000..0ae12c0 --- /dev/null +++ b/install-sh @@ -0,0 +1,401 @@ +#!/bin/sh +# install - install a program, script, or datafile + +scriptversion=2005-11-07.23 + +# This originates from X11R5 (mit/util/scripts/install.sh), which was +# later released in X11R6 (xc/config/util/install.sh) with the +# following copyright and license. +# +# Copyright (C) 1994 X Consortium +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- +# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# Except as contained in this notice, the name of the X Consortium shall not +# be used in advertising or otherwise to promote the sale, use or other deal- +# ings in this Software without prior written authorization from the X Consor- +# tium. +# +# +# FSF changes to this file are in the public domain. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# `make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. It can only install one file at a time, a restriction +# shared with many OS's install programs. + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit="${DOITPROG-}" + +# put in absolute paths if you don't have them in your path; or use env. vars. + +mvprog="${MVPROG-mv}" +cpprog="${CPPROG-cp}" +chmodprog="${CHMODPROG-chmod}" +chownprog="${CHOWNPROG-chown}" +chgrpprog="${CHGRPPROG-chgrp}" +stripprog="${STRIPPROG-strip}" +rmprog="${RMPROG-rm}" +mkdirprog="${MKDIRPROG-mkdir}" + +posix_glob= +posix_mkdir= + +# Symbolic mode for testing mkdir with directories. +# It is the same as 755, but also tests that "u+" works. +test_mode=u=rwx,g=rx,o=rx,u+wx + +# Desired mode of installed file. +mode=0755 + +# Desired mode of newly created intermediate directories. +# It is empty if not known yet. +intermediate_mode= + +chmodcmd=$chmodprog +chowncmd= +chgrpcmd= +stripcmd= +rmcmd="$rmprog -f" +mvcmd="$mvprog" +src= +dst= +dir_arg= +dstarg= +no_target_directory= + +usage="Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE + or: $0 [OPTION]... SRCFILES... DIRECTORY + or: $0 [OPTION]... -t DIRECTORY SRCFILES... + or: $0 [OPTION]... -d DIRECTORIES... + +In the 1st form, copy SRCFILE to DSTFILE. +In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. +In the 4th, create DIRECTORIES. + +Options: +-c (ignored) +-d create directories instead of installing files. +-g GROUP $chgrpprog installed files to GROUP. +-m MODE $chmodprog installed files to MODE. +-o USER $chownprog installed files to USER. +-s $stripprog installed files. +-t DIRECTORY install into DIRECTORY. +-T report an error if DSTFILE is a directory. +--help display this help and exit. +--version display version info and exit. + +Environment variables override the default commands: + CHGRPPROG CHMODPROG CHOWNPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG +" + +while test -n "$1"; do + case $1 in + -c) shift + continue;; + + -d) dir_arg=true + shift + continue;; + + -g) chgrpcmd="$chgrpprog $2" + shift + shift + continue;; + + --help) echo "$usage"; exit $?;; + + -m) mode=$2 + shift + shift + continue;; + + -o) chowncmd="$chownprog $2" + shift + shift + continue;; + + -s) stripcmd=$stripprog + shift + continue;; + + -t) dstarg=$2 + shift + shift + continue;; + + -T) no_target_directory=true + shift + continue;; + + --version) echo "$0 $scriptversion"; exit $?;; + + *) # When -d is used, all remaining arguments are directories to create. + # When -t is used, the destination is already specified. + test -n "$dir_arg$dstarg" && break + # Otherwise, the last argument is the destination. Remove it from $@. + for arg + do + if test -n "$dstarg"; then + # $@ is not empty: it contains at least $arg. + set fnord "$@" "$dstarg" + shift # fnord + fi + shift # arg + dstarg=$arg + done + break;; + esac +done + +if test -z "$1"; then + if test -z "$dir_arg"; then + echo "$0: no input file specified." >&2 + exit 1 + fi + # It's OK to call `install-sh -d' without argument. + # This can happen when creating conditional directories. + exit 0 +fi + +test -n "$dir_arg" || trap '(exit $?); exit' 1 2 13 15 + +for src +do + # Protect names starting with `-'. + case $src in + -*) src=./$src ;; + esac + + if test -n "$dir_arg"; then + dst=$src + dstdir=$dst + test -d "$dstdir" + dstdir_status=$? + else + + # Waiting for this to be detected by the "$cpprog $src $dsttmp" command + # might cause directories to be created, which would be especially bad + # if $src (and thus $dsttmp) contains '*'. + if test ! -f "$src" && test ! -d "$src"; then + echo "$0: $src does not exist." >&2 + exit 1 + fi + + if test -z "$dstarg"; then + echo "$0: no destination specified." >&2 + exit 1 + fi + + dst=$dstarg + # Protect names starting with `-'. + case $dst in + -*) dst=./$dst ;; + esac + + # If destination is a directory, append the input filename; won't work + # if double slashes aren't ignored. + if test -d "$dst"; then + if test -n "$no_target_directory"; then + echo "$0: $dstarg: Is a directory" >&2 + exit 1 + fi + dstdir=$dst + dst=$dstdir/`basename "$src"` + dstdir_status=0 + else + # Prefer dirname, but fall back on a substitute if dirname fails. + dstdir=` + (dirname "$dst") 2>/dev/null || + expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$dst" : 'X\(//\)[^/]' \| \ + X"$dst" : 'X\(//\)$' \| \ + X"$dst" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || + echo X"$dst" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q' + ` + + test -d "$dstdir" + dstdir_status=$? + fi + fi + + obsolete_mkdir_used=false + + if test $dstdir_status != 0; then + case $posix_mkdir in + '') + posix_mkdir=false + if $mkdirprog -m $test_mode -p -- / >/dev/null 2>&1; then + posix_mkdir=true + else + # Remove any dirs left behind by ancient mkdir implementations. + rmdir ./-m "$test_mode" ./-p ./-- 2>/dev/null + fi ;; + esac + + if + $posix_mkdir && { + + # With -d, create the new directory with the user-specified mode. + # Otherwise, create it using the same intermediate mode that + # mkdir -p would use when creating intermediate directories. + # POSIX says that this mode is "$(umask -S),u+wx", so use that + # if umask -S works. + + if test -n "$dir_arg"; then + mkdir_mode=$mode + else + case $intermediate_mode in + '') + if umask_S=`(umask -S) 2>/dev/null`; then + intermediate_mode=$umask_S,u+wx + else + intermediate_mode=$test_mode + fi ;; + esac + mkdir_mode=$intermediate_mode + fi + + $mkdirprog -m "$mkdir_mode" -p -- "$dstdir" + } + then : + else + + # mkdir does not conform to POSIX, or it failed possibly due to + # a race condition. Create the directory the slow way, step by + # step, checking for races as we go. + + case $dstdir in + /*) pathcomp=/ ;; + -*) pathcomp=./ ;; + *) pathcomp= ;; + esac + + case $posix_glob in + '') + if (set -f) 2>/dev/null; then + posix_glob=true + else + posix_glob=false + fi ;; + esac + + oIFS=$IFS + IFS=/ + $posix_glob && set -f + set fnord $dstdir + shift + $posix_glob && set +f + IFS=$oIFS + + for d + do + test "x$d" = x && continue + + pathcomp=$pathcomp$d + if test ! -d "$pathcomp"; then + $mkdirprog "$pathcomp" + # Don't fail if two instances are running concurrently. + test -d "$pathcomp" || exit 1 + fi + pathcomp=$pathcomp/ + done + obsolete_mkdir_used=true + fi + fi + + if test -n "$dir_arg"; then + { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && + { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && + { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || + test -z "$chmodcmd" || $doit $chmodcmd "$mode" "$dst"; } || exit 1 + else + + # Make a couple of temp file names in the proper directory. + dsttmp=$dstdir/_inst.$$_ + rmtmp=$dstdir/_rm.$$_ + + # Trap to clean up those temp files at exit. + trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 + + # Copy the file name to the temp name. + $doit $cpprog "$src" "$dsttmp" && + + # and set any options; do chmod last to preserve setuid bits. + # + # If any of these fail, we abort the whole thing. If we want to + # ignore errors from any of these, just make sure not to ignore + # errors from the above "$doit $cpprog $src $dsttmp" command. + # + { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } \ + && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } \ + && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } \ + && { test -z "$chmodcmd" || $doit $chmodcmd "$mode" "$dsttmp"; } && + + # Now rename the file to the real destination. + { $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null \ + || { + # The rename failed, perhaps because mv can't rename something else + # to itself, or perhaps because mv is so ancient that it does not + # support -f. + + # Now remove or move aside any old file at destination location. + # We try this two ways since rm can't unlink itself on some + # systems and the destination file might be busy for other + # reasons. In this case, the final cleanup might fail but the new + # file should still install successfully. + { + if test -f "$dst"; then + $doit $rmcmd -f "$dst" 2>/dev/null \ + || { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null \ + && { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }; }\ + || { + echo "$0: cannot unlink or rename $dst" >&2 + (exit 1); exit 1 + } + else + : + fi + } && + + # Now rename the file to the real destination. + $doit $mvcmd "$dsttmp" "$dst" + } + } || exit 1 + + trap '' 0 + fi +done + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-end: "$" +# End: diff --git a/src/Makefile.SH b/src/Makefile.in similarity index 66% rename from src/Makefile.SH rename to src/Makefile.in index c5e20d8..98034ec 100644 --- a/src/Makefile.SH +++ b/src/Makefile.in @@ -1,104 +1,47 @@ -case $CONFIG in -'') - if test -f config.sh; then TOP=.; - elif test -f ../config.sh; then TOP=..; - elif test -f ../../config.sh; then TOP=../..; - elif test -f ../../../config.sh; then TOP=../../..; - elif test -f ../../../../config.sh; then TOP=../../../..; - else - echo "Can't find config.sh."; exit 1 - fi - . $TOP/config.sh - ;; -esac -: This forces SH files to create target in same directory as SH file. -: This is so that make depend always knows where to find SH derivatives. -case "$0" in -*/*) cd `expr X$0 : 'X\(.*\)/'` ;; -esac -echo "Extracting Makefile (with variable substitutions)" -if test "x$OSTYPE" = "xmsys"; then - OUTFILES="buildinf netmud" -else - OUTFILES="buildinf netmud info_slave console" -fi -: This section of the file will have variable substitutions done on it. -: Move anything that needs config subs from !NO!SUBS! section to !GROK!THIS!. -: Protect any dollar signs and backticks that you do not want interpreted -: by putting a backslash in front. You may delete these comments. -$spitshell >Makefile <>Makefile <<'!NO!SUBS!' - -# stupid SYS V shell -SHELL=/bin/sh - -# for lint target -LINT=lint -LINTFLAGS=-haz $(DEFINES) -LINTFILT=egrep -v '(possible pointer|long assign|not yet im|:$$)' +OUTFILES=buildinf netmud info_slave -# Libs -LIBS=$(CLIBS) $(RLIBS) $(ILIBS) -CC=libtool +# Libs EXCEPT for SQL ones +LIBS=$(CLIBS) +LIBTOOL=libtool -CFLAGS=$(CCFLAGS) $(RDEFS) $(IDEFS) - -# 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 cmds.c \ - command.c compress.c conf.c cque.c create.c cron.c db.c destroy.c division.c extchat.c \ - extmail.c filecopy.c flags.c funcrypt.c function.c \ - fundb.c fundiv.c funlist.c funmath.c funmisc.c funstr.c funtime.c \ - funufun.c game.c help.c htab.c ident.c lock.c log.c look.c \ - malias.c match.c memcheck.c move.c modules.c mushlua.c mushlua_wrap.c mycrypt.c mymalloc.c mysocket.c \ - myssl.c notify.c parse.c pcre.c player.c plyrlist.c \ - predicat.c privtab.c prog.o ptab.c rob.c services.c set.c shs.c \ - sig.c speech.c sql.c strdup.c strtree.c strutil.c tables.c timer.c unparse.c \ - utils.c version.c warnings.c wild.c wiz.c +C_FILES=access.c atr_tab.c attrib.c boolexp.c bsd.c bufferq.c chunk.c \ + cmds.c command.c compress.c conf.c cque.c create.c cron.c \ + db.c destroy.c division.c extchat.c extmail.c filecopy.c \ + flags.c funcrypt.c function.c fundb.c funlist.c \ + funmath.c funmisc.c funstr.c funtime.c funufun.c game.c help.c \ + htab.c ident.c intmap.c lock.c log.c look.c malias.c \ + markup.c match.c memcheck.c modules.c move.c mycrypt.c mymalloc.c \ + mysocket.c myrlimit.c myssl.c mushlua.o mushlua_wrap.o notify.c \ + parse.c pcre.c player.c \ + plyrlist.c predicat.c privtab.c prog.c info_master.c ptab.c rob.c \ + services.c set.c shs.c sig.c sort.c speech.c sql.c strdup.c \ + strtree.c strutil.c tables.c timer.c unparse.c utils.c \ + version.c wait.c warnings.c wild.c wiz.c -H_FILES = ../config.h ../confmagic.h ../hdrs/ansi.h ../hdrs/atr_tab.h \ - ../hdrs/attrib.h ../hdrs/boolexp.h ../hdrs/bufferq.h ../hdrs/case.h \ - ../hdrs/case.h ../hdrs/chunk.h ../hdrs/command.h ../hdrs/conf.h \ - ../hdrs/copyrite.h ../hdrs/dbdefs.h ../hdrs/dbio.h ../hdrs/extchat.h \ - ../hdrs/externs.h ../hdrs/extmail.h ../hdrs/flags.h \ - ../hdrs/function.h ../hdrs/game.h ../hdrs/getpgsiz.h ../hdrs/help.h \ - ../hdrs/htab.h ../hdrs/htab.h ../hdrs/ident.h ../hdrs/lock.h \ - ../hdrs/log.h ../hdrs/log.h ../hdrs/malias.h ../hdrs/match.h \ - ../hdrs/modules.h ../hdrs/mushdb.h ../hdrs/mushlua.h ../hdrs/mushtype.h \ - ../hdrs/mymalloc.h ../hdrs/mysocket.h ../hdrs/myssl.h \ - ../hdrs/parse.h ../hdrs/pcre.h ../hdrs/privtab.h ../hdrs/ptab.h \ - ../hdrs/strtree.h ../hdrs/version.h ../options.h ../hdrs/division.h ../hdrs/cron.h # .o versions of above - these are used in the build -COMMON_O_FILES=access.o atr_tab.o attrib.o boolexp.o bufferq.o \ - chunk.o cmds.o \ - command.o compress.o conf.o cque.o create.o cron.o db.o destroy.o division.o extchat.o \ - extmail.o filecopy.o flags.o funcrypt.o function.o \ - fundb.o funlist.o fundiv.o funmath.o funmisc.o funstr.o funtime.o \ - funufun.o game.o help.o htab.o ident.o lock.o log.o look.o \ - malias.o match.o memcheck.o move.o modules.o mushlua.o mushlua_wrap.o mycrypt.o mymalloc.o \ - mysocket.o myssl.o notify.o parse.o pcre.o player.o plyrlist.o predicat.o privtab.o \ - prog.o ptab.o rob.o rplog.o services.o set.o shs.o sig.o speech.o sql.o strdup.o \ - strtree.o strutil.o tables.o timer.o unparse.o utils.o version.o warnings.o \ - wild.o wiz.o - -O_FILES=$(COMMON_O_FILES) bsd.o -CONSOLE_O_FILES=$(COMMON_O_FILES) console.o +O_FILES=access.o atr_tab.o attrib.o boolexp.o bsd.o bufferq.o chunk.o \ + cmds.o command.o compress.o conf.o cque.o create.o cron.o \ + db.o destroy.o division.o extchat.o extmail.o filecopy.o \ + flags.o funcrypt.o fundiv.o function.o fundb.o funlist.o \ + funmath.o funmisc.o funstr.o funtime.o funufun.o game.o help.o \ + htab.o ident.o intmap.o lock.o log.o look.o malias.o \ + markup.o match.o memcheck.o move.o modules.o mushlua.o mushlua_wrap.o \ + mycrypt.o mymalloc.o \ + mysocket.o myrlimit.o myssl.o notify.o parse.o pcre.o player.o \ + plyrlist.o prog.o info_master.o predicat.o privtab.o ptab.o rob.o \ + services.o set.o shs.o sig.o sort.o speech.o sql.o strdup.o \ + strtree.o strutil.o tables.o timer.o unparse.o utils.o \ + version.o wait.o warnings.o wild.o wiz.o # This is a dummy target, in case you type 'make' in the source # directory (likely for emacs users who M-x compile.) @@ -111,97 +54,109 @@ all: $(OUTFILES) netmud: $(O_FILES) @echo "Making netmud." -mv -f netmud netmud~ - $(LIBTOOL) --mode=link $(CC) -export-dynamic $(LDFLAGS) $(CCFLAGS) -o netmud $(O_FILES) $(LIBS) - -console: $(CONSOLE_O_FILES) - @echo "Making console." - -mv -f console console~ - $(LIBTOOL) --mode=link $(CC) -export-dynamic $(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) + $(LIBTOOL) --mode=link $(CC) -export-dynamic $(LDFLAGS) $(SQL_LDFLAGS) $(CCFLAGS) -o netmud $(O_FILES) $(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 mymalloc.o mysocket.c +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 mymalloc.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) -c ssl_slave.c + $(CC) $(CCFLAGS) -o ssl_slave ssl_slave.o \ + $(SSL_SLAVE_OBJS) $(LDFLAGS) $(LIBS) -# ../hdrs/buildinf.h contains build information used by version.c: -# time/date of build and CFLAGS # It should always be out of date. buildinf: -rm -f ../hdrs/buildinf.h @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 mushlua_wrap.c: mushlua.i @echo "Generating mushlua_wrap.c" swig -o mushlua_wrap.c -lua mushlua.i + +../hdrs/patches.h: + if [ ! -f ../hdrs/patches.h ]; then \ + (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 ../*.h ../hdrs/*.h + @ETAGS@ *.c ../hdrs/*.h ctags: - ctags *.c + @CTAGS@ *.c ../hdrs/*.h - makedepend -fMakefile.SH -w10 -- -I../hdrs -I.. $(CFLAGS) -- $(C_FILES) $(H_FILES) - perl ../utils/fixdepend.pl Makefile.SH +depend: funlocal.c cmdlocal.c local.c flaglocal.c + makedepend -fMakefile.in -w10 -- $(CFLAGS) -- $(C_FILES) $(H_FILES) + @PERL@ ../utils/fixdepend.pl Makefile.in # Requires GNU indent 1.2 or better! indent: (set +e; for file in *.dst *.c ../hdrs/*.h ; do echo $$file; \ - /usr/bin/indent -npro -kr -ci2 -ss -psl -ip4 -i2 -cs -l80 -lc75 -nut \ - -T atr_err -T ATRALIAS -T DESC -T CNode -T CONF -T BQUE -T FUN \ - -T NVAL -T i_rec -T f_rec -T USERFN_ENTRY -T PRIV -T FLAG \ - -T FLAGENT -T FLAG_ALIAS -T tlist -T u -T stat -T tcheck -T ATTR \ - -T ALIST -T CHTAB -T FBLKHDR -T FBLOCK -T OPTTAB -T dbref \ - -T object_flag_type -T channel_type -T boolexp_type -T CHAN \ - -T mail_flag -T help_indx -T lock_type -T lock_list -T MEM \ - -T warn_type -T POWER -T POWER_ALIAS -T acsflag -T StrTree \ - -T switch_mask -T COMLIST -T COMALIAS -T COMMAND -T SWITCH_VALUE \ - -T COMSORTSTRUC -T CHANUSER -T Signal_t -T Sigfunc -T univptr_t \ - -T __ptr_t -T __malloc_size_t -T HASHENT -T HASHTAB -T COMMAND_INFO \ - -T CHANLIST -T Malloc_t -T Free_t -T MATH -T socklen_t \ - -T StrNode -T IDENT -T Size_t -T Port_t -T help_file -T PTAB \ - -T SHS_INFO -T ansi_string -T MAIL $$file ; done) + @INDENT@ -npro -kr -ci2 -ss -psl -ip4 -i2 -cs -l80 -lc75 -nut \ + -T accent_info -T acsflag -T aig_func -T ALIST -T ansi_data \ + -T ansi_string -T atr_err -T ATRALIAS -T ATTR -T BOOL -T boolexp \ + -T boolexp_type -T BQUE -T branch_chain -T BUFFERQ -T bvm_opcode \ + -T BYTE -T CDESC -T CHAN -T CHANLIST -T CHANUSER \ + -T chunk_reference_t -T CNode -T COMLIST -T command_func \ + -T COMMAND_INFO -T comp_func -T compile_data -T COMSORTSTRUC \ + -T config_func -T CType -T dbref -T Debug_Info -T DESC \ + -T dfa_match_data -T eptrblock -T EVAL_CONTEXT -T FBLOCK \ + -T fd_type -T FLAG -T FLAG_ALIAS -T FLAGSPACE -T folder_array \ + -T FUN -T function_func -T FUNTAB -T GLOBALTAB -T hash_func \ + -T HASHENT -T HASHTAB -T heapframe -T help_file -T help_indx \ + -T ident_t -T im_key -T imaxdiv_t -T intmap -T IVAL \ + -T list_type_list -T lock_list -T lock_type -T LOCKMSGINFO \ + -T LONG -T ltype -T MAIL -T mail_flag -T makerecord \ + -T markup_information -T match_data -T MATH -T MEM -T na_lookup \ + -T NVAL -T object_flag_type -T OPTTAB -T patricia \ + -T 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 SHS_INFO \ + -T slab -T sqlplatform -T STFunc -T StrNode -T StrTree \ + -T switch_mask -T SWITCH_VALUE -T tcheck -T tlist \ + -T ucp_type_table -T UIVAL -T uschar -T UsedAttr -T USERFN_ENTRY \ + -T WAIT_TYPE -T warn_type -T Word \ + $$file ; done) clean: -rm -f *.o -rm -f a.out core gmon.out $(OUTFILES) distclean: clean - -rm -f *~ *.orig *.rej *.bak \#* + -rm -f *~ *.orig *.rej *.bak funlocal.c cmdlocal.c flaglocal.c local.c \#* test_compress: comp_h.c $(CC) $(CFLAGS) -o test_compress -DSTANDALONE comp_h.c -portmsg: portmsg.c mysocket.c sig.o +portmsg: portmsg.c mysocket.c sig.o wait.o $(CC) $(CCFLAGS) -DINFOSLAVE -o portmsg portmsg.c mysocket.c sig.o \ - $(LDFLAGS) $(LIBS) + wait.o $(LDFLAGS) $(LIBS) # Some dependencies that make depend doesn't handle well compress.o: comp_h.c comp_w.c comp_w8.c -version.o: ../hdrs/buildinf.h -cmds.o: ../hdrs/funs.h ../hdrs/cmds.h - -# CobraMUSH no-network console -console.o: bsd.c - $(CC) $(CFLAGS) -DCOMPILE_CONSOLE -o console.o -c bsd.c # DO NOT DELETE THIS LINE -- make depend depends on it. @@ -217,10 +172,9 @@ access.o: ../hdrs/dbdefs.h access.o: ../hdrs/mushdb.h access.o: ../hdrs/flags.h access.o: ../hdrs/ptab.h -access.o: ../hdrs/division.h access.o: ../hdrs/chunk.h -access.o: ../hdrs/bufferq.h access.o: ../confmagic.h +access.o: ../hdrs/mypcre.h access.o: ../hdrs/access.h access.o: ../hdrs/mymalloc.h access.o: ../hdrs/match.h @@ -238,14 +192,10 @@ atr_tab.o: ../hdrs/dbdefs.h atr_tab.o: ../hdrs/mushdb.h atr_tab.o: ../hdrs/flags.h atr_tab.o: ../hdrs/ptab.h -atr_tab.o: ../hdrs/division.h atr_tab.o: ../hdrs/chunk.h -atr_tab.o: ../hdrs/bufferq.h atr_tab.o: ../confmagic.h +atr_tab.o: ../hdrs/mypcre.h atr_tab.o: ../hdrs/attrib.h -atr_tab.o: ../hdrs/boolexp.h -atr_tab.o: ../hdrs/command.h -atr_tab.o: ../hdrs/switches.h atr_tab.o: ../hdrs/atr_tab.h atr_tab.o: ../hdrs/privtab.h atr_tab.o: ../hdrs/mymalloc.h @@ -263,20 +213,17 @@ attrib.o: ../hdrs/dbdefs.h attrib.o: ../hdrs/mushdb.h attrib.o: ../hdrs/flags.h attrib.o: ../hdrs/ptab.h -attrib.o: ../hdrs/division.h attrib.o: ../hdrs/chunk.h -attrib.o: ../hdrs/bufferq.h attrib.o: ../confmagic.h +attrib.o: ../hdrs/mypcre.h attrib.o: ../hdrs/attrib.h -attrib.o: ../hdrs/boolexp.h -attrib.o: ../hdrs/command.h -attrib.o: ../hdrs/switches.h attrib.o: ../hdrs/match.h attrib.o: ../hdrs/parse.h attrib.o: ../hdrs/privtab.h attrib.o: ../hdrs/mymalloc.h attrib.o: ../hdrs/strtree.h attrib.o: ../hdrs/lock.h +attrib.o: ../hdrs/boolexp.h attrib.o: ../hdrs/log.h boolexp.o: ../hdrs/copyrite.h boolexp.o: ../config.h @@ -284,26 +231,25 @@ boolexp.o: ../hdrs/conf.h boolexp.o: ../options.h boolexp.o: ../hdrs/mushtype.h boolexp.o: ../hdrs/htab.h +boolexp.o: ../hdrs/dbdefs.h boolexp.o: ../hdrs/mushdb.h boolexp.o: ../hdrs/flags.h boolexp.o: ../hdrs/ptab.h -boolexp.o: ../hdrs/division.h +boolexp.o: ../hdrs/chunk.h boolexp.o: ../hdrs/match.h boolexp.o: ../hdrs/externs.h boolexp.o: ../hdrs/compile.h -boolexp.o: ../hdrs/dbdefs.h -boolexp.o: ../hdrs/chunk.h -boolexp.o: ../hdrs/bufferq.h boolexp.o: ../confmagic.h +boolexp.o: ../hdrs/mypcre.h boolexp.o: ../hdrs/lock.h boolexp.o: ../hdrs/boolexp.h boolexp.o: ../hdrs/parse.h boolexp.o: ../hdrs/attrib.h -boolexp.o: ../hdrs/command.h -boolexp.o: ../hdrs/switches.h boolexp.o: ../hdrs/log.h 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 @@ -316,10 +262,9 @@ bsd.o: ../hdrs/dbdefs.h bsd.o: ../hdrs/mushdb.h bsd.o: ../hdrs/flags.h bsd.o: ../hdrs/ptab.h -bsd.o: ../hdrs/division.h bsd.o: ../hdrs/chunk.h -bsd.o: ../hdrs/bufferq.h bsd.o: ../confmagic.h +bsd.o: ../hdrs/mypcre.h bsd.o: ../hdrs/lock.h bsd.o: ../hdrs/boolexp.h bsd.o: ../hdrs/help.h @@ -331,17 +276,19 @@ bsd.o: ../hdrs/access.h bsd.o: ../hdrs/command.h bsd.o: ../hdrs/switches.h bsd.o: ../hdrs/version.h +bsd.o: ../hdrs/patches.h bsd.o: ../hdrs/mysocket.h bsd.o: ../hdrs/ident.h +bsd.o: ../hdrs/lookup.h bsd.o: ../hdrs/strtree.h bsd.o: ../hdrs/log.h -bsd.o: ../hdrs/pcre.h bsd.o: ../hdrs/myssl.h bsd.o: ../hdrs/mymalloc.h bsd.o: ../hdrs/extmail.h bsd.o: ../hdrs/attrib.h bsd.o: ../hdrs/game.h bsd.o: ../hdrs/dbio.h +bsd.o: ../hdrs/intmap.h bufferq.o: ../hdrs/copyrite.h bufferq.o: ../config.h bufferq.o: ../hdrs/conf.h @@ -354,10 +301,10 @@ bufferq.o: ../hdrs/dbdefs.h bufferq.o: ../hdrs/mushdb.h bufferq.o: ../hdrs/flags.h bufferq.o: ../hdrs/ptab.h -bufferq.o: ../hdrs/division.h bufferq.o: ../hdrs/chunk.h -bufferq.o: ../hdrs/bufferq.h bufferq.o: ../confmagic.h +bufferq.o: ../hdrs/mypcre.h +bufferq.o: ../hdrs/bufferq.h bufferq.o: ../hdrs/mymalloc.h bufferq.o: ../hdrs/log.h chunk.o: ../hdrs/copyrite.h @@ -372,16 +319,33 @@ chunk.o: ../hdrs/dbdefs.h chunk.o: ../hdrs/mushdb.h chunk.o: ../hdrs/flags.h chunk.o: ../hdrs/ptab.h -chunk.o: ../hdrs/division.h chunk.o: ../hdrs/chunk.h -chunk.o: ../hdrs/bufferq.h chunk.o: ../confmagic.h -chunk.o: ../hdrs/boolexp.h +chunk.o: ../hdrs/mypcre.h chunk.o: ../hdrs/command.h chunk.o: ../hdrs/switches.h chunk.o: ../hdrs/intrface.h chunk.o: ../hdrs/log.h chunk.o: ../hdrs/mymalloc.h +cmdlocal.o: ../hdrs/copyrite.h +cmdlocal.o: ../config.h +cmdlocal.o: ../hdrs/conf.h +cmdlocal.o: ../options.h +cmdlocal.o: ../hdrs/mushtype.h +cmdlocal.o: ../hdrs/htab.h +cmdlocal.o: ../hdrs/externs.h +cmdlocal.o: ../hdrs/compile.h +cmdlocal.o: ../hdrs/dbdefs.h +cmdlocal.o: ../hdrs/mushdb.h +cmdlocal.o: ../hdrs/flags.h +cmdlocal.o: ../hdrs/ptab.h +cmdlocal.o: ../hdrs/chunk.h +cmdlocal.o: ../confmagic.h +cmdlocal.o: ../hdrs/mypcre.h +cmdlocal.o: ../hdrs/parse.h +cmdlocal.o: ../hdrs/command.h +cmdlocal.o: ../hdrs/switches.h +cmdlocal.o: ../hdrs/cmds.h cmds.o: ../hdrs/copyrite.h cmds.o: ../config.h cmds.o: ../hdrs/conf.h @@ -394,24 +358,22 @@ cmds.o: ../hdrs/dbdefs.h cmds.o: ../hdrs/mushdb.h cmds.o: ../hdrs/flags.h cmds.o: ../hdrs/ptab.h -cmds.o: ../hdrs/division.h cmds.o: ../hdrs/chunk.h -cmds.o: ../hdrs/bufferq.h cmds.o: ../confmagic.h +cmds.o: ../hdrs/mypcre.h cmds.o: ../hdrs/match.h cmds.o: ../hdrs/game.h cmds.o: ../hdrs/attrib.h -cmds.o: ../hdrs/boolexp.h -cmds.o: ../hdrs/command.h -cmds.o: ../hdrs/switches.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 cmds.o: ../hdrs/lock.h +cmds.o: ../hdrs/boolexp.h cmds.o: ../hdrs/function.h +cmds.o: ../hdrs/command.h +cmds.o: ../hdrs/switches.h cmds.o: ../hdrs/log.h command.o: ../hdrs/copyrite.h command.o: ../config.h @@ -425,24 +387,23 @@ command.o: ../hdrs/dbdefs.h command.o: ../hdrs/mushdb.h command.o: ../hdrs/flags.h command.o: ../hdrs/ptab.h -command.o: ../hdrs/division.h command.o: ../hdrs/chunk.h -command.o: ../hdrs/bufferq.h command.o: ../confmagic.h +command.o: ../hdrs/mypcre.h command.o: ../hdrs/game.h command.o: ../hdrs/match.h command.o: ../hdrs/attrib.h -command.o: ../hdrs/boolexp.h -command.o: ../hdrs/command.h -command.o: ../hdrs/switches.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 +command.o: ../hdrs/strtree.h command.o: ../hdrs/function.h +command.o: ../hdrs/command.h +command.o: ../hdrs/switches.h command.o: ../hdrs/mymalloc.h command.o: ../hdrs/log.h +command.o: ../hdrs/sort.h command.o: ../hdrs/cmds.h command.o: switchinc.c compress.o: ../config.h @@ -450,7 +411,7 @@ compress.o: ../options.h compress.o: ../hdrs/mushtype.h compress.o: ../hdrs/copyrite.h compress.o: ../hdrs/log.h -compress.o: comp_w.c +compress.o: comp_h.c compress.o: ../hdrs/conf.h compress.o: ../hdrs/htab.h compress.o: ../hdrs/externs.h @@ -459,10 +420,9 @@ compress.o: ../hdrs/dbdefs.h compress.o: ../hdrs/mushdb.h compress.o: ../hdrs/flags.h compress.o: ../hdrs/ptab.h -compress.o: ../hdrs/division.h compress.o: ../hdrs/chunk.h -compress.o: ../hdrs/bufferq.h compress.o: ../confmagic.h +compress.o: ../hdrs/mypcre.h compress.o: ../hdrs/mymalloc.h conf.o: ../hdrs/copyrite.h conf.o: ../config.h @@ -476,13 +436,12 @@ conf.o: ../hdrs/dbdefs.h conf.o: ../hdrs/mushdb.h conf.o: ../hdrs/flags.h conf.o: ../hdrs/ptab.h -conf.o: ../hdrs/division.h conf.o: ../hdrs/chunk.h -conf.o: ../hdrs/bufferq.h conf.o: ../confmagic.h +conf.o: ../hdrs/mypcre.h +conf.o: ../hdrs/ansi.h conf.o: ../hdrs/pueblo.h conf.o: ../hdrs/parse.h -conf.o: ../hdrs/boolexp.h conf.o: ../hdrs/command.h conf.o: ../hdrs/switches.h conf.o: ../hdrs/log.h @@ -496,26 +455,25 @@ cque.o: ../hdrs/conf.h cque.o: ../options.h cque.o: ../hdrs/mushtype.h cque.o: ../hdrs/htab.h -cque.o: ../hdrs/boolexp.h -cque.o: ../hdrs/chunk.h cque.o: ../hdrs/command.h -cque.o: ../hdrs/division.h -cque.o: ../hdrs/ptab.h cque.o: ../hdrs/switches.h cque.o: ../hdrs/mushdb.h cque.o: ../hdrs/flags.h +cque.o: ../hdrs/ptab.h cque.o: ../hdrs/match.h cque.o: ../hdrs/externs.h cque.o: ../hdrs/compile.h cque.o: ../hdrs/dbdefs.h -cque.o: ../hdrs/bufferq.h +cque.o: ../hdrs/chunk.h cque.o: ../confmagic.h +cque.o: ../hdrs/mypcre.h cque.o: ../hdrs/parse.h cque.o: ../hdrs/strtree.h cque.o: ../hdrs/mymalloc.h cque.o: ../hdrs/game.h cque.o: ../hdrs/attrib.h cque.o: ../hdrs/log.h +cque.o: ../hdrs/intmap.h create.o: ../hdrs/copyrite.h create.o: ../config.h create.o: ../hdrs/conf.h @@ -528,46 +486,20 @@ create.o: ../hdrs/dbdefs.h create.o: ../hdrs/mushdb.h create.o: ../hdrs/flags.h create.o: ../hdrs/ptab.h -create.o: ../hdrs/division.h create.o: ../hdrs/chunk.h -create.o: ../hdrs/bufferq.h create.o: ../confmagic.h +create.o: ../hdrs/mypcre.h create.o: ../hdrs/attrib.h -create.o: ../hdrs/boolexp.h -create.o: ../hdrs/command.h -create.o: ../hdrs/switches.h create.o: ../hdrs/match.h create.o: ../hdrs/extchat.h +create.o: ../hdrs/boolexp.h +create.o: ../hdrs/bufferq.h create.o: ../hdrs/log.h create.o: ../hdrs/lock.h create.o: ../hdrs/parse.h create.o: ../hdrs/game.h -cron.o: ../hdrs/copyrite.h -cron.o: ../config.h -cron.o: ../hdrs/conf.h -cron.o: ../options.h -cron.o: ../hdrs/mushtype.h -cron.o: ../hdrs/htab.h -cron.o: ../hdrs/externs.h -cron.o: ../hdrs/compile.h -cron.o: ../hdrs/dbdefs.h -cron.o: ../hdrs/mushdb.h -cron.o: ../hdrs/flags.h -cron.o: ../hdrs/ptab.h -cron.o: ../hdrs/division.h -cron.o: ../hdrs/chunk.h -cron.o: ../hdrs/bufferq.h -cron.o: ../confmagic.h -cron.o: ../hdrs/parse.h -cron.o: ../hdrs/privtab.h -cron.o: ../hdrs/attrib.h -cron.o: ../hdrs/boolexp.h -cron.o: ../hdrs/command.h -cron.o: ../hdrs/switches.h -cron.o: ../hdrs/lock.h -cron.o: ../hdrs/log.h -cron.o: ../hdrs/match.h -cron.o: ../hdrs/cron.h +create.o: ../hdrs/command.h +create.o: ../hdrs/switches.h db.o: ../hdrs/copyrite.h db.o: ../config.h db.o: ../hdrs/conf.h @@ -581,22 +513,22 @@ db.o: ../hdrs/dbdefs.h db.o: ../hdrs/mushdb.h db.o: ../hdrs/flags.h db.o: ../hdrs/ptab.h -db.o: ../hdrs/division.h db.o: ../hdrs/chunk.h -db.o: ../hdrs/bufferq.h db.o: ../confmagic.h +db.o: ../hdrs/mypcre.h db.o: ../hdrs/attrib.h -db.o: ../hdrs/boolexp.h -db.o: ../hdrs/command.h -db.o: ../hdrs/switches.h db.o: ../hdrs/mymalloc.h db.o: ../hdrs/game.h db.o: ../hdrs/lock.h +db.o: ../hdrs/boolexp.h db.o: ../hdrs/log.h db.o: ../hdrs/strtree.h db.o: ../hdrs/parse.h db.o: ../hdrs/privtab.h +db.o: ../hdrs/extchat.h +db.o: ../hdrs/bufferq.h db.o: ../hdrs/extmail.h +db.o: ../hdrs/ansi.h destroy.o: ../config.h destroy.o: ../hdrs/copyrite.h destroy.o: ../hdrs/conf.h @@ -606,49 +538,20 @@ destroy.o: ../hdrs/htab.h destroy.o: ../hdrs/mushdb.h destroy.o: ../hdrs/flags.h destroy.o: ../hdrs/ptab.h -destroy.o: ../hdrs/division.h destroy.o: ../hdrs/match.h destroy.o: ../hdrs/externs.h destroy.o: ../hdrs/compile.h destroy.o: ../hdrs/dbdefs.h destroy.o: ../hdrs/chunk.h -destroy.o: ../hdrs/bufferq.h destroy.o: ../confmagic.h +destroy.o: ../hdrs/mypcre.h destroy.o: ../hdrs/log.h destroy.o: ../hdrs/game.h destroy.o: ../hdrs/extmail.h destroy.o: ../hdrs/malias.h destroy.o: ../hdrs/attrib.h -destroy.o: ../hdrs/boolexp.h -destroy.o: ../hdrs/command.h -destroy.o: ../hdrs/switches.h destroy.o: ../hdrs/lock.h -division.o: ../hdrs/copyrite.h -division.o: ../config.h -division.o: ../hdrs/conf.h -division.o: ../options.h -division.o: ../hdrs/mushtype.h -division.o: ../hdrs/htab.h -division.o: ../hdrs/externs.h -division.o: ../hdrs/compile.h -division.o: ../hdrs/dbdefs.h -division.o: ../hdrs/mushdb.h -division.o: ../hdrs/flags.h -division.o: ../hdrs/ptab.h -division.o: ../hdrs/division.h -division.o: ../hdrs/chunk.h -division.o: ../hdrs/bufferq.h -division.o: ../confmagic.h -division.o: ../hdrs/boolexp.h -division.o: ../hdrs/command.h -division.o: ../hdrs/switches.h -division.o: ../hdrs/parse.h -division.o: ../hdrs/cmds.h -division.o: ../hdrs/dbio.h -division.o: ../hdrs/match.h -division.o: ../hdrs/log.h -division.o: ../hdrs/attrib.h -division.o: ../hdrs/ansi.h +destroy.o: ../hdrs/boolexp.h extchat.o: ../hdrs/copyrite.h extchat.o: ../config.h extchat.o: ../hdrs/conf.h @@ -661,16 +564,14 @@ extchat.o: ../hdrs/dbdefs.h extchat.o: ../hdrs/mushdb.h extchat.o: ../hdrs/flags.h extchat.o: ../hdrs/ptab.h -extchat.o: ../hdrs/division.h extchat.o: ../hdrs/chunk.h -extchat.o: ../hdrs/bufferq.h extchat.o: ../confmagic.h +extchat.o: ../hdrs/mypcre.h extchat.o: ../hdrs/attrib.h -extchat.o: ../hdrs/boolexp.h -extchat.o: ../hdrs/command.h -extchat.o: ../hdrs/switches.h extchat.o: ../hdrs/match.h extchat.o: ../hdrs/extchat.h +extchat.o: ../hdrs/boolexp.h +extchat.o: ../hdrs/bufferq.h extchat.o: ../hdrs/ansi.h extchat.o: ../hdrs/privtab.h extchat.o: ../hdrs/mymalloc.h @@ -680,6 +581,8 @@ extchat.o: ../hdrs/lock.h extchat.o: ../hdrs/log.h extchat.o: ../hdrs/game.h extchat.o: ../hdrs/function.h +extchat.o: ../hdrs/command.h +extchat.o: ../hdrs/switches.h extchat.o: ../hdrs/dbio.h extmail.o: ../config.h extmail.o: ../hdrs/copyrite.h @@ -693,23 +596,57 @@ extmail.o: ../hdrs/dbdefs.h extmail.o: ../hdrs/mushdb.h extmail.o: ../hdrs/flags.h extmail.o: ../hdrs/ptab.h -extmail.o: ../hdrs/division.h extmail.o: ../hdrs/chunk.h -extmail.o: ../hdrs/bufferq.h extmail.o: ../confmagic.h +extmail.o: ../hdrs/mypcre.h extmail.o: ../hdrs/match.h extmail.o: ../hdrs/extmail.h +extmail.o: ../hdrs/function.h extmail.o: ../hdrs/malias.h extmail.o: ../hdrs/attrib.h -extmail.o: ../hdrs/boolexp.h -extmail.o: ../hdrs/command.h -extmail.o: ../hdrs/switches.h extmail.o: ../hdrs/parse.h extmail.o: ../hdrs/mymalloc.h +extmail.o: ../hdrs/ansi.h extmail.o: ../hdrs/pueblo.h extmail.o: ../hdrs/log.h extmail.o: ../hdrs/lock.h +extmail.o: ../hdrs/boolexp.h +extmail.o: ../hdrs/command.h +extmail.o: ../hdrs/switches.h extmail.o: ../hdrs/dbio.h +filecopy.o: ../hdrs/copyrite.h +filecopy.o: ../config.h +filecopy.o: ../hdrs/conf.h +filecopy.o: ../options.h +filecopy.o: ../hdrs/mushtype.h +filecopy.o: ../hdrs/htab.h +filecopy.o: ../hdrs/mushdb.h +filecopy.o: ../hdrs/flags.h +filecopy.o: ../hdrs/ptab.h +filecopy.o: ../hdrs/match.h +filecopy.o: ../hdrs/externs.h +filecopy.o: ../hdrs/compile.h +filecopy.o: ../hdrs/dbdefs.h +filecopy.o: ../hdrs/chunk.h +filecopy.o: ../confmagic.h +filecopy.o: ../hdrs/mypcre.h +filecopy.o: ../hdrs/mymalloc.h +filecopy.o: ../hdrs/log.h +flaglocal.o: ../hdrs/copyrite.h +flaglocal.o: ../config.h +flaglocal.o: ../hdrs/conf.h +flaglocal.o: ../options.h +flaglocal.o: ../hdrs/mushtype.h +flaglocal.o: ../hdrs/htab.h +flaglocal.o: ../hdrs/externs.h +flaglocal.o: ../hdrs/compile.h +flaglocal.o: ../hdrs/dbdefs.h +flaglocal.o: ../hdrs/mushdb.h +flaglocal.o: ../hdrs/flags.h +flaglocal.o: ../hdrs/ptab.h +flaglocal.o: ../hdrs/chunk.h +flaglocal.o: ../confmagic.h +flaglocal.o: ../hdrs/mypcre.h flags.o: ../config.h flags.o: ../hdrs/conf.h flags.o: ../hdrs/copyrite.h @@ -722,11 +659,9 @@ flags.o: ../hdrs/dbdefs.h flags.o: ../hdrs/mushdb.h flags.o: ../hdrs/flags.h flags.o: ../hdrs/ptab.h -flags.o: ../hdrs/division.h flags.o: ../hdrs/chunk.h -flags.o: ../hdrs/bufferq.h flags.o: ../confmagic.h -flags.o: ../hdrs/boolexp.h +flags.o: ../hdrs/mypcre.h flags.o: ../hdrs/command.h flags.o: ../hdrs/switches.h flags.o: ../hdrs/attrib.h @@ -735,10 +670,12 @@ flags.o: ../hdrs/match.h flags.o: ../hdrs/privtab.h flags.o: ../hdrs/game.h flags.o: ../hdrs/lock.h +flags.o: ../hdrs/boolexp.h 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 -flags.o: ../hdrs/ansi.h funcrypt.o: ../hdrs/copyrite.h funcrypt.o: ../config.h funcrypt.o: ../hdrs/conf.h @@ -752,13 +689,13 @@ funcrypt.o: ../hdrs/dbdefs.h funcrypt.o: ../hdrs/mushdb.h funcrypt.o: ../hdrs/flags.h funcrypt.o: ../hdrs/ptab.h -funcrypt.o: ../hdrs/division.h funcrypt.o: ../hdrs/chunk.h -funcrypt.o: ../hdrs/bufferq.h funcrypt.o: ../confmagic.h +funcrypt.o: ../hdrs/mypcre.h funcrypt.o: ../hdrs/version.h funcrypt.o: ../hdrs/extchat.h funcrypt.o: ../hdrs/boolexp.h +funcrypt.o: ../hdrs/bufferq.h funcrypt.o: ../hdrs/parse.h funcrypt.o: ../hdrs/function.h funcrypt.o: ../hdrs/command.h @@ -779,21 +716,20 @@ function.o: ../hdrs/dbdefs.h function.o: ../hdrs/mushdb.h function.o: ../hdrs/flags.h function.o: ../hdrs/ptab.h -function.o: ../hdrs/division.h function.o: ../hdrs/chunk.h -function.o: ../hdrs/bufferq.h function.o: ../confmagic.h +function.o: ../hdrs/mypcre.h function.o: ../hdrs/attrib.h -function.o: ../hdrs/boolexp.h -function.o: ../hdrs/command.h -function.o: ../hdrs/switches.h function.o: ../hdrs/function.h function.o: ../hdrs/match.h function.o: ../hdrs/parse.h function.o: ../hdrs/lock.h +function.o: ../hdrs/boolexp.h function.o: ../hdrs/game.h function.o: ../hdrs/mymalloc.h +function.o: ../hdrs/sort.h function.o: ../hdrs/funs.h +function.o: ../hdrs/ansi.h fundb.o: ../hdrs/copyrite.h fundb.o: ../config.h fundb.o: ../hdrs/conf.h @@ -806,51 +742,22 @@ fundb.o: ../hdrs/dbdefs.h fundb.o: ../hdrs/mushdb.h fundb.o: ../hdrs/flags.h fundb.o: ../hdrs/ptab.h -fundb.o: ../hdrs/division.h fundb.o: ../hdrs/chunk.h -fundb.o: ../hdrs/bufferq.h fundb.o: ../confmagic.h +fundb.o: ../hdrs/mypcre.h fundb.o: ../hdrs/match.h fundb.o: ../hdrs/parse.h -fundb.o: ../hdrs/boolexp.h fundb.o: ../hdrs/command.h fundb.o: ../hdrs/switches.h fundb.o: ../hdrs/game.h fundb.o: ../hdrs/privtab.h fundb.o: ../hdrs/lock.h +fundb.o: ../hdrs/boolexp.h fundb.o: ../hdrs/log.h fundb.o: ../hdrs/attrib.h fundb.o: ../hdrs/function.h -fundiv.o: ../hdrs/copyrite.h -fundiv.o: ../config.h -fundiv.o: ../hdrs/conf.h -fundiv.o: ../options.h -fundiv.o: ../hdrs/mushtype.h -fundiv.o: ../hdrs/htab.h -fundiv.o: ../hdrs/externs.h -fundiv.o: ../hdrs/compile.h -fundiv.o: ../hdrs/dbdefs.h -fundiv.o: ../hdrs/mushdb.h -fundiv.o: ../hdrs/flags.h -fundiv.o: ../hdrs/ptab.h -fundiv.o: ../hdrs/division.h -fundiv.o: ../hdrs/chunk.h -fundiv.o: ../hdrs/bufferq.h -fundiv.o: ../confmagic.h -fundiv.o: ../hdrs/match.h -fundiv.o: ../hdrs/parse.h -fundiv.o: ../hdrs/boolexp.h -fundiv.o: ../hdrs/command.h -fundiv.o: ../hdrs/switches.h -fundiv.o: ../hdrs/game.h -fundiv.o: ../hdrs/privtab.h -fundiv.o: ../hdrs/lock.h -fundiv.o: ../hdrs/log.h -fundiv.o: ../hdrs/attrib.h -fundiv.o: ../hdrs/extchat.h funlist.o: ../hdrs/copyrite.h funlist.o: ../config.h -funlist.o: ../hdrs/ansi.h funlist.o: ../hdrs/conf.h funlist.o: ../options.h funlist.o: ../hdrs/mushtype.h @@ -862,20 +769,37 @@ funlist.o: ../hdrs/dbdefs.h funlist.o: ../hdrs/mushdb.h funlist.o: ../hdrs/flags.h funlist.o: ../hdrs/ptab.h -funlist.o: ../hdrs/division.h funlist.o: ../hdrs/chunk.h -funlist.o: ../hdrs/bufferq.h funlist.o: ../confmagic.h +funlist.o: ../hdrs/mypcre.h +funlist.o: ../hdrs/ansi.h funlist.o: ../hdrs/parse.h -funlist.o: ../hdrs/boolexp.h funlist.o: ../hdrs/function.h funlist.o: ../hdrs/mymalloc.h -funlist.o: ../hdrs/pcre.h funlist.o: ../hdrs/match.h -funlist.o: ../hdrs/attrib.h funlist.o: ../hdrs/command.h funlist.o: ../hdrs/switches.h +funlist.o: ../hdrs/attrib.h funlist.o: ../hdrs/lock.h +funlist.o: ../hdrs/boolexp.h +funlist.o: ../hdrs/sort.h +funlocal.o: ../hdrs/copyrite.h +funlocal.o: ../config.h +funlocal.o: ../hdrs/conf.h +funlocal.o: ../options.h +funlocal.o: ../hdrs/mushtype.h +funlocal.o: ../hdrs/htab.h +funlocal.o: ../hdrs/externs.h +funlocal.o: ../hdrs/compile.h +funlocal.o: ../hdrs/dbdefs.h +funlocal.o: ../hdrs/mushdb.h +funlocal.o: ../hdrs/flags.h +funlocal.o: ../hdrs/ptab.h +funlocal.o: ../hdrs/chunk.h +funlocal.o: ../confmagic.h +funlocal.o: ../hdrs/mypcre.h +funlocal.o: ../hdrs/parse.h +funlocal.o: ../hdrs/function.h funmath.o: ../hdrs/copyrite.h funmath.o: ../config.h funmath.o: ../hdrs/conf.h @@ -888,11 +812,12 @@ funmath.o: ../hdrs/dbdefs.h funmath.o: ../hdrs/mushdb.h funmath.o: ../hdrs/flags.h funmath.o: ../hdrs/ptab.h -funmath.o: ../hdrs/division.h funmath.o: ../hdrs/chunk.h -funmath.o: ../hdrs/bufferq.h funmath.o: ../confmagic.h +funmath.o: ../hdrs/mypcre.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 @@ -906,10 +831,9 @@ funmisc.o: ../hdrs/dbdefs.h funmisc.o: ../hdrs/mushdb.h funmisc.o: ../hdrs/flags.h funmisc.o: ../hdrs/ptab.h -funmisc.o: ../hdrs/division.h funmisc.o: ../hdrs/chunk.h -funmisc.o: ../hdrs/bufferq.h funmisc.o: ../confmagic.h +funmisc.o: ../hdrs/mypcre.h funmisc.o: ../hdrs/version.h funmisc.o: ../hdrs/lock.h funmisc.o: ../hdrs/boolexp.h @@ -920,32 +844,31 @@ funmisc.o: ../hdrs/command.h funmisc.o: ../hdrs/switches.h funmisc.o: ../hdrs/game.h funmisc.o: ../hdrs/attrib.h +funmisc.o: ../hdrs/ansi.h funstr.o: ../hdrs/copyrite.h funstr.o: ../config.h funstr.o: ../hdrs/conf.h funstr.o: ../options.h funstr.o: ../hdrs/mushtype.h funstr.o: ../hdrs/htab.h -funstr.o: ../hdrs/ansi.h funstr.o: ../hdrs/externs.h funstr.o: ../hdrs/compile.h funstr.o: ../hdrs/dbdefs.h funstr.o: ../hdrs/mushdb.h funstr.o: ../hdrs/flags.h funstr.o: ../hdrs/ptab.h -funstr.o: ../hdrs/division.h funstr.o: ../hdrs/chunk.h -funstr.o: ../hdrs/bufferq.h funstr.o: ../confmagic.h +funstr.o: ../hdrs/mypcre.h +funstr.o: ../hdrs/ansi.h funstr.o: ../hdrs/case.h funstr.o: ../hdrs/match.h funstr.o: ../hdrs/parse.h funstr.o: ../hdrs/pueblo.h funstr.o: ../hdrs/attrib.h -funstr.o: ../hdrs/boolexp.h -funstr.o: ../hdrs/command.h -funstr.o: ../hdrs/switches.h funstr.o: ../hdrs/lock.h +funstr.o: ../hdrs/boolexp.h +funstr.o: ../hdrs/sort.h funtime.o: ../hdrs/copyrite.h funtime.o: ../config.h funtime.o: ../hdrs/conf.h @@ -958,17 +881,13 @@ funtime.o: ../hdrs/dbdefs.h funtime.o: ../hdrs/mushdb.h funtime.o: ../hdrs/flags.h funtime.o: ../hdrs/ptab.h -funtime.o: ../hdrs/division.h funtime.o: ../hdrs/chunk.h -funtime.o: ../hdrs/bufferq.h funtime.o: ../confmagic.h +funtime.o: ../hdrs/mypcre.h funtime.o: ../hdrs/parse.h funtime.o: ../hdrs/log.h funtime.o: ../hdrs/match.h funtime.o: ../hdrs/attrib.h -funtime.o: ../hdrs/boolexp.h -funtime.o: ../hdrs/command.h -funtime.o: ../hdrs/switches.h funufun.o: ../hdrs/copyrite.h funufun.o: ../config.h funufun.o: ../hdrs/conf.h @@ -981,18 +900,15 @@ funufun.o: ../hdrs/dbdefs.h funufun.o: ../hdrs/mushdb.h funufun.o: ../hdrs/flags.h funufun.o: ../hdrs/ptab.h -funufun.o: ../hdrs/division.h funufun.o: ../hdrs/chunk.h -funufun.o: ../hdrs/bufferq.h funufun.o: ../confmagic.h +funufun.o: ../hdrs/mypcre.h funufun.o: ../hdrs/match.h funufun.o: ../hdrs/parse.h funufun.o: ../hdrs/mymalloc.h funufun.o: ../hdrs/attrib.h -funufun.o: ../hdrs/boolexp.h -funufun.o: ../hdrs/command.h -funufun.o: ../hdrs/switches.h funufun.o: ../hdrs/lock.h +funufun.o: ../hdrs/boolexp.h game.o: ../hdrs/copyrite.h game.o: ../config.h game.o: ../hdrs/conf.h @@ -1005,31 +921,32 @@ game.o: ../hdrs/dbdefs.h game.o: ../hdrs/mushdb.h game.o: ../hdrs/flags.h game.o: ../hdrs/ptab.h -game.o: ../hdrs/division.h game.o: ../hdrs/chunk.h -game.o: ../hdrs/bufferq.h game.o: ../confmagic.h +game.o: ../hdrs/mypcre.h game.o: ../hdrs/game.h game.o: ../hdrs/attrib.h -game.o: ../hdrs/boolexp.h -game.o: ../hdrs/command.h -game.o: ../hdrs/switches.h game.o: ../hdrs/match.h game.o: ../hdrs/case.h game.o: ../hdrs/extmail.h game.o: ../hdrs/extchat.h +game.o: ../hdrs/boolexp.h +game.o: ../hdrs/bufferq.h game.o: ../hdrs/myssl.h game.o: ../hdrs/getpgsiz.h game.o: ../hdrs/parse.h game.o: ../hdrs/access.h game.o: ../hdrs/version.h game.o: ../hdrs/strtree.h +game.o: ../hdrs/command.h +game.o: ../hdrs/switches.h +game.o: ../hdrs/intmap.h game.o: ../hdrs/log.h game.o: ../hdrs/lock.h game.o: ../hdrs/function.h game.o: ../hdrs/help.h game.o: ../hdrs/dbio.h -game.o: ../hdrs/pcre.h +game.o: ../hdrs/ansi.h help.o: ../config.h help.o: ../hdrs/conf.h help.o: ../hdrs/copyrite.h @@ -1042,11 +959,9 @@ help.o: ../hdrs/dbdefs.h help.o: ../hdrs/mushdb.h help.o: ../hdrs/flags.h help.o: ../hdrs/ptab.h -help.o: ../hdrs/division.h help.o: ../hdrs/chunk.h -help.o: ../hdrs/bufferq.h help.o: ../confmagic.h -help.o: ../hdrs/boolexp.h +help.o: ../hdrs/mypcre.h help.o: ../hdrs/command.h help.o: ../hdrs/switches.h help.o: ../hdrs/help.h @@ -1067,10 +982,9 @@ htab.o: ../hdrs/dbdefs.h htab.o: ../hdrs/mushdb.h htab.o: ../hdrs/flags.h htab.o: ../hdrs/ptab.h -htab.o: ../hdrs/division.h htab.o: ../hdrs/chunk.h -htab.o: ../hdrs/bufferq.h htab.o: ../confmagic.h +htab.o: ../hdrs/mypcre.h htab.o: ../hdrs/mymalloc.h ident.o: ../config.h ident.o: ../hdrs/conf.h @@ -1084,17 +998,51 @@ ident.o: ../hdrs/dbdefs.h ident.o: ../hdrs/mushdb.h ident.o: ../hdrs/flags.h ident.o: ../hdrs/ptab.h -ident.o: ../hdrs/division.h ident.o: ../hdrs/chunk.h -ident.o: ../hdrs/bufferq.h ident.o: ../confmagic.h +ident.o: ../hdrs/mypcre.h ident.o: ../hdrs/attrib.h -ident.o: ../hdrs/boolexp.h -ident.o: ../hdrs/command.h -ident.o: ../hdrs/switches.h ident.o: ../hdrs/ident.h ident.o: ../hdrs/mysocket.h ident.o: ../hdrs/mymalloc.h +intmap.o: ../config.h +intmap.o: ../hdrs/conf.h +intmap.o: ../hdrs/copyrite.h +intmap.o: ../options.h +intmap.o: ../hdrs/mushtype.h +intmap.o: ../hdrs/htab.h +intmap.o: ../hdrs/externs.h +intmap.o: ../hdrs/compile.h +intmap.o: ../hdrs/dbdefs.h +intmap.o: ../hdrs/mushdb.h +intmap.o: ../hdrs/flags.h +intmap.o: ../hdrs/ptab.h +intmap.o: ../hdrs/chunk.h +intmap.o: ../confmagic.h +intmap.o: ../hdrs/mypcre.h +intmap.o: ../hdrs/mymalloc.h +intmap.o: ../hdrs/intmap.h +local.o: ../hdrs/copyrite.h +local.o: ../config.h +local.o: ../hdrs/conf.h +local.o: ../options.h +local.o: ../hdrs/mushtype.h +local.o: ../hdrs/htab.h +local.o: ../hdrs/dbio.h +local.o: ../hdrs/externs.h +local.o: ../hdrs/compile.h +local.o: ../hdrs/dbdefs.h +local.o: ../hdrs/mushdb.h +local.o: ../hdrs/flags.h +local.o: ../hdrs/ptab.h +local.o: ../hdrs/chunk.h +local.o: ../confmagic.h +local.o: ../hdrs/mypcre.h +local.o: ../hdrs/parse.h +local.o: ../hdrs/command.h +local.o: ../hdrs/switches.h +local.o: ../hdrs/lock.h +local.o: ../hdrs/boolexp.h lock.o: ../hdrs/copyrite.h lock.o: ../config.h lock.o: ../hdrs/conf.h @@ -1107,14 +1055,11 @@ lock.o: ../hdrs/dbdefs.h lock.o: ../hdrs/mushdb.h lock.o: ../hdrs/flags.h lock.o: ../hdrs/ptab.h -lock.o: ../hdrs/division.h lock.o: ../hdrs/chunk.h -lock.o: ../hdrs/bufferq.h lock.o: ../confmagic.h +lock.o: ../hdrs/mypcre.h lock.o: ../hdrs/boolexp.h lock.o: ../hdrs/attrib.h -lock.o: ../hdrs/command.h -lock.o: ../hdrs/switches.h lock.o: ../hdrs/lock.h lock.o: ../hdrs/match.h lock.o: ../hdrs/log.h @@ -1134,10 +1079,10 @@ log.o: ../hdrs/dbdefs.h log.o: ../hdrs/mushdb.h log.o: ../hdrs/flags.h log.o: ../hdrs/ptab.h -log.o: ../hdrs/division.h log.o: ../hdrs/chunk.h -log.o: ../hdrs/bufferq.h log.o: ../confmagic.h +log.o: ../hdrs/mypcre.h +log.o: ../hdrs/bufferq.h log.o: ../hdrs/log.h look.o: ../config.h look.o: ../hdrs/copyrite.h @@ -1151,20 +1096,20 @@ look.o: ../hdrs/dbdefs.h look.o: ../hdrs/mushdb.h look.o: ../hdrs/flags.h look.o: ../hdrs/ptab.h -look.o: ../hdrs/division.h look.o: ../hdrs/chunk.h -look.o: ../hdrs/bufferq.h look.o: ../confmagic.h +look.o: ../hdrs/mypcre.h look.o: ../hdrs/lock.h look.o: ../hdrs/boolexp.h look.o: ../hdrs/attrib.h -look.o: ../hdrs/command.h -look.o: ../hdrs/switches.h look.o: ../hdrs/match.h look.o: ../hdrs/ansi.h look.o: ../hdrs/pueblo.h look.o: ../hdrs/extchat.h +look.o: ../hdrs/bufferq.h look.o: ../hdrs/game.h +look.o: ../hdrs/command.h +look.o: ../hdrs/switches.h look.o: ../hdrs/parse.h look.o: ../hdrs/privtab.h look.o: ../hdrs/log.h @@ -1180,10 +1125,9 @@ malias.o: ../hdrs/dbdefs.h malias.o: ../hdrs/mushdb.h malias.o: ../hdrs/flags.h malias.o: ../hdrs/ptab.h -malias.o: ../hdrs/division.h malias.o: ../hdrs/chunk.h -malias.o: ../hdrs/bufferq.h malias.o: ../confmagic.h +malias.o: ../hdrs/mypcre.h malias.o: ../hdrs/match.h malias.o: ../hdrs/parse.h malias.o: ../hdrs/malias.h @@ -1192,6 +1136,29 @@ malias.o: ../hdrs/mymalloc.h malias.o: ../hdrs/pueblo.h malias.o: ../hdrs/log.h malias.o: ../hdrs/dbio.h +markup.o: ../config.h +markup.o: ../hdrs/copyrite.h +markup.o: ../hdrs/conf.h +markup.o: ../options.h +markup.o: ../hdrs/mushtype.h +markup.o: ../hdrs/htab.h +markup.o: ../hdrs/case.h +markup.o: ../hdrs/pueblo.h +markup.o: ../hdrs/parse.h +markup.o: ../confmagic.h +markup.o: ../hdrs/externs.h +markup.o: ../hdrs/compile.h +markup.o: ../hdrs/dbdefs.h +markup.o: ../hdrs/mushdb.h +markup.o: ../hdrs/flags.h +markup.o: ../hdrs/ptab.h +markup.o: ../hdrs/chunk.h +markup.o: ../hdrs/mypcre.h +markup.o: ../hdrs/ansi.h +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 @@ -1201,13 +1168,12 @@ match.o: ../hdrs/htab.h match.o: ../hdrs/mushdb.h match.o: ../hdrs/flags.h match.o: ../hdrs/ptab.h -match.o: ../hdrs/division.h match.o: ../hdrs/externs.h match.o: ../hdrs/compile.h match.o: ../hdrs/dbdefs.h match.o: ../hdrs/chunk.h -match.o: ../hdrs/bufferq.h match.o: ../confmagic.h +match.o: ../hdrs/mypcre.h match.o: ../hdrs/case.h match.o: ../hdrs/match.h match.o: ../hdrs/parse.h @@ -1223,10 +1189,9 @@ memcheck.o: ../hdrs/dbdefs.h memcheck.o: ../hdrs/mushdb.h memcheck.o: ../hdrs/flags.h memcheck.o: ../hdrs/ptab.h -memcheck.o: ../hdrs/division.h memcheck.o: ../hdrs/chunk.h -memcheck.o: ../hdrs/bufferq.h memcheck.o: ../confmagic.h +memcheck.o: ../hdrs/mypcre.h memcheck.o: ../hdrs/mymalloc.h memcheck.o: ../hdrs/log.h move.o: ../hdrs/copyrite.h @@ -1241,18 +1206,17 @@ move.o: ../hdrs/dbdefs.h move.o: ../hdrs/mushdb.h move.o: ../hdrs/flags.h move.o: ../hdrs/ptab.h -move.o: ../hdrs/division.h move.o: ../hdrs/chunk.h -move.o: ../hdrs/bufferq.h move.o: ../confmagic.h +move.o: ../hdrs/mypcre.h move.o: ../hdrs/attrib.h -move.o: ../hdrs/boolexp.h -move.o: ../hdrs/command.h -move.o: ../hdrs/switches.h move.o: ../hdrs/match.h move.o: ../hdrs/lock.h +move.o: ../hdrs/boolexp.h move.o: ../hdrs/parse.h move.o: ../hdrs/log.h +move.o: ../hdrs/command.h +move.o: ../hdrs/switches.h move.o: ../hdrs/cmds.h move.o: ../hdrs/game.h mycrypt.o: ../config.h @@ -1264,7 +1228,22 @@ mycrypt.o: ../hdrs/htab.h 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/mypcre.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 @@ -1277,13 +1256,28 @@ mysocket.o: ../hdrs/dbdefs.h mysocket.o: ../hdrs/mushdb.h mysocket.o: ../hdrs/flags.h mysocket.o: ../hdrs/ptab.h -mysocket.o: ../hdrs/division.h mysocket.o: ../hdrs/chunk.h -mysocket.o: ../hdrs/bufferq.h mysocket.o: ../confmagic.h +mysocket.o: ../hdrs/mypcre.h mysocket.o: ../hdrs/mymalloc.h mysocket.o: ../hdrs/mysocket.h mysocket.o: ../hdrs/ident.h +myrlimit.o: ../hdrs/copyrite.h +myrlimit.o: ../config.h +myrlimit.o: ../hdrs/conf.h +myrlimit.o: ../options.h +myrlimit.o: ../hdrs/mushtype.h +myrlimit.o: ../hdrs/htab.h +myrlimit.o: ../hdrs/version.h +myrlimit.o: ../hdrs/externs.h +myrlimit.o: ../hdrs/compile.h +myrlimit.o: ../hdrs/dbdefs.h +myrlimit.o: ../hdrs/mushdb.h +myrlimit.o: ../hdrs/flags.h +myrlimit.o: ../hdrs/ptab.h +myrlimit.o: ../hdrs/chunk.h +myrlimit.o: ../confmagic.h +myrlimit.o: ../hdrs/mypcre.h myssl.o: ../hdrs/copyrite.h myssl.o: ../config.h myssl.o: ../hdrs/conf.h @@ -1292,6 +1286,14 @@ myssl.o: ../hdrs/mushtype.h myssl.o: ../hdrs/htab.h myssl.o: ../hdrs/mysocket.h myssl.o: ../confmagic.h +myssl.o: ../hdrs/externs.h +myssl.o: ../hdrs/compile.h +myssl.o: ../hdrs/dbdefs.h +myssl.o: ../hdrs/mushdb.h +myssl.o: ../hdrs/flags.h +myssl.o: ../hdrs/ptab.h +myssl.o: ../hdrs/chunk.h +myssl.o: ../hdrs/mypcre.h myssl.o: ../hdrs/myssl.h myssl.o: ../hdrs/log.h myssl.o: ../hdrs/parse.h @@ -1304,13 +1306,12 @@ notify.o: ../hdrs/htab.h notify.o: ../hdrs/mushdb.h notify.o: ../hdrs/flags.h notify.o: ../hdrs/ptab.h -notify.o: ../hdrs/division.h notify.o: ../hdrs/externs.h notify.o: ../hdrs/compile.h notify.o: ../hdrs/dbdefs.h notify.o: ../hdrs/chunk.h -notify.o: ../hdrs/bufferq.h notify.o: ../confmagic.h +notify.o: ../hdrs/mypcre.h notify.o: ../hdrs/lock.h notify.o: ../hdrs/boolexp.h notify.o: ../hdrs/help.h @@ -1320,16 +1321,16 @@ notify.o: ../hdrs/pueblo.h notify.o: ../hdrs/parse.h notify.o: ../hdrs/access.h notify.o: ../hdrs/version.h +notify.o: ../hdrs/patches.h notify.o: ../hdrs/mysocket.h notify.o: ../hdrs/ident.h notify.o: ../hdrs/strtree.h notify.o: ../hdrs/log.h notify.o: ../hdrs/mymalloc.h notify.o: ../hdrs/extchat.h +notify.o: ../hdrs/bufferq.h notify.o: ../hdrs/extmail.h notify.o: ../hdrs/attrib.h -notify.o: ../hdrs/command.h -notify.o: ../hdrs/switches.h notify.o: ../hdrs/game.h parse.o: ../hdrs/copyrite.h parse.o: ../config.h @@ -1343,25 +1344,19 @@ parse.o: ../hdrs/dbdefs.h parse.o: ../hdrs/mushdb.h parse.o: ../hdrs/flags.h parse.o: ../hdrs/ptab.h -parse.o: ../hdrs/division.h parse.o: ../hdrs/chunk.h -parse.o: ../hdrs/bufferq.h parse.o: ../confmagic.h +parse.o: ../hdrs/mypcre.h parse.o: ../hdrs/ansi.h -parse.o: ../hdrs/boolexp.h parse.o: ../hdrs/function.h parse.o: ../hdrs/case.h parse.o: ../hdrs/match.h parse.o: ../hdrs/parse.h parse.o: ../hdrs/attrib.h -parse.o: ../hdrs/command.h -parse.o: ../hdrs/switches.h -parse.o: ../hdrs/pcre.h parse.o: ../hdrs/log.h parse.o: ../hdrs/mymalloc.h pcre.o: ../config.h -pcre.o: ../hdrs/pcre.h -pcre.o: ../confmagic.h +pcre.o: ../hdrs/mypcre.h player.o: ../hdrs/copyrite.h player.o: ../config.h player.o: ../hdrs/conf.h @@ -1374,19 +1369,16 @@ player.o: ../hdrs/dbdefs.h player.o: ../hdrs/mushdb.h player.o: ../hdrs/flags.h player.o: ../hdrs/ptab.h -player.o: ../hdrs/division.h player.o: ../hdrs/chunk.h -player.o: ../hdrs/bufferq.h player.o: ../confmagic.h +player.o: ../hdrs/mypcre.h player.o: ../hdrs/attrib.h -player.o: ../hdrs/boolexp.h -player.o: ../hdrs/command.h -player.o: ../hdrs/switches.h player.o: ../hdrs/access.h -player.o: ../hdrs/parse.h player.o: ../hdrs/mymalloc.h player.o: ../hdrs/log.h player.o: ../hdrs/lock.h +player.o: ../hdrs/boolexp.h +player.o: ../hdrs/parse.h player.o: ../hdrs/extmail.h plyrlist.o: ../config.h plyrlist.o: ../hdrs/copyrite.h @@ -1400,14 +1392,11 @@ plyrlist.o: ../hdrs/dbdefs.h plyrlist.o: ../hdrs/mushdb.h plyrlist.o: ../hdrs/flags.h plyrlist.o: ../hdrs/ptab.h -plyrlist.o: ../hdrs/division.h plyrlist.o: ../hdrs/chunk.h -plyrlist.o: ../hdrs/bufferq.h plyrlist.o: ../confmagic.h +plyrlist.o: ../hdrs/mypcre.h plyrlist.o: ../hdrs/attrib.h -plyrlist.o: ../hdrs/boolexp.h -plyrlist.o: ../hdrs/command.h -plyrlist.o: ../hdrs/switches.h +plyrlist.o: ../hdrs/mymalloc.h predicat.o: ../hdrs/copyrite.h predicat.o: ../config.h predicat.o: ../hdrs/conf.h @@ -1420,15 +1409,12 @@ predicat.o: ../hdrs/dbdefs.h predicat.o: ../hdrs/mushdb.h predicat.o: ../hdrs/flags.h predicat.o: ../hdrs/ptab.h -predicat.o: ../hdrs/division.h predicat.o: ../hdrs/chunk.h -predicat.o: ../hdrs/bufferq.h predicat.o: ../confmagic.h +predicat.o: ../hdrs/mypcre.h predicat.o: ../hdrs/attrib.h -predicat.o: ../hdrs/boolexp.h -predicat.o: ../hdrs/command.h -predicat.o: ../hdrs/switches.h predicat.o: ../hdrs/lock.h +predicat.o: ../hdrs/boolexp.h predicat.o: ../hdrs/match.h predicat.o: ../hdrs/ansi.h predicat.o: ../hdrs/parse.h @@ -1448,9 +1434,28 @@ privtab.o: ../hdrs/dbdefs.h privtab.o: ../hdrs/mushdb.h privtab.o: ../hdrs/flags.h privtab.o: ../hdrs/ptab.h -privtab.o: ../hdrs/division.h privtab.o: ../hdrs/chunk.h -privtab.o: ../hdrs/bufferq.h +privtab.o: ../hdrs/mypcre.h +info_master.o: ../hdrs/copyrite.h +info_master.o: ../config.h +info_master.o: ../hdrs/conf.h +info_master.o: ../options.h +info_master.o: ../hdrs/mushtype.h +info_master.o: ../hdrs/htab.h +info_master.o: ../hdrs/externs.h +info_master.o: ../hdrs/compile.h +info_master.o: ../hdrs/dbdefs.h +info_master.o: ../hdrs/mushdb.h +info_master.o: ../hdrs/flags.h +info_master.o: ../hdrs/ptab.h +info_master.o: ../hdrs/chunk.h +info_master.o: ../confmagic.h +info_master.o: ../hdrs/mypcre.h +info_master.o: ../hdrs/access.h +info_master.o: ../hdrs/mysocket.h +info_master.o: ../hdrs/ident.h +info_master.o: ../hdrs/lookup.h +info_master.o: ../hdrs/log.h ptab.o: ../config.h ptab.o: ../hdrs/copyrite.h ptab.o: ../hdrs/conf.h @@ -1463,10 +1468,9 @@ ptab.o: ../hdrs/dbdefs.h ptab.o: ../hdrs/mushdb.h ptab.o: ../hdrs/flags.h ptab.o: ../hdrs/ptab.h -ptab.o: ../hdrs/division.h ptab.o: ../hdrs/chunk.h -ptab.o: ../hdrs/bufferq.h ptab.o: ../confmagic.h +ptab.o: ../hdrs/mypcre.h rob.o: ../config.h rob.o: ../hdrs/copyrite.h rob.o: ../hdrs/conf.h @@ -1479,45 +1483,19 @@ rob.o: ../hdrs/dbdefs.h rob.o: ../hdrs/mushdb.h rob.o: ../hdrs/flags.h rob.o: ../hdrs/ptab.h -rob.o: ../hdrs/division.h rob.o: ../hdrs/chunk.h -rob.o: ../hdrs/bufferq.h rob.o: ../confmagic.h +rob.o: ../hdrs/mypcre.h rob.o: ../hdrs/attrib.h -rob.o: ../hdrs/boolexp.h -rob.o: ../hdrs/command.h -rob.o: ../hdrs/switches.h rob.o: ../hdrs/match.h rob.o: ../hdrs/parse.h rob.o: ../hdrs/log.h rob.o: ../hdrs/lock.h +rob.o: ../hdrs/boolexp.h rob.o: ../hdrs/game.h rob.o: ../hdrs/case.h -rplog.o: ../hdrs/copyrite.h -rplog.o: ../config.h -rplog.o: ../hdrs/conf.h -rplog.o: ../options.h -rplog.o: ../hdrs/mushtype.h -rplog.o: ../hdrs/htab.h -rplog.o: ../hdrs/externs.h -rplog.o: ../hdrs/compile.h -rplog.o: ../hdrs/dbdefs.h -rplog.o: ../hdrs/mushdb.h -rplog.o: ../hdrs/flags.h -rplog.o: ../hdrs/ptab.h -rplog.o: ../hdrs/division.h -rplog.o: ../hdrs/chunk.h -rplog.o: ../hdrs/bufferq.h -rplog.o: ../confmagic.h -rplog.o: ../hdrs/parse.h -rplog.o: ../hdrs/command.h -rplog.o: ../hdrs/boolexp.h -rplog.o: ../hdrs/switches.h -rplog.o: ../hdrs/cmds.h -rplog.o: ../hdrs/attrib.h -rplog.o: ../hdrs/match.h -rplog.o: ../hdrs/ansi.h -rplog.o: ../hdrs/log.h +services.o: ../hdrs/copyrite.h +services.o: ../config.h set.o: ../hdrs/copyrite.h set.o: ../config.h set.o: ../hdrs/conf.h @@ -1530,20 +1508,19 @@ set.o: ../hdrs/dbdefs.h set.o: ../hdrs/mushdb.h set.o: ../hdrs/flags.h set.o: ../hdrs/ptab.h -set.o: ../hdrs/division.h set.o: ../hdrs/chunk.h -set.o: ../hdrs/bufferq.h set.o: ../confmagic.h -set.o: ../hdrs/game.h +set.o: ../hdrs/mypcre.h set.o: ../hdrs/match.h set.o: ../hdrs/attrib.h -set.o: ../hdrs/boolexp.h +set.o: ../hdrs/ansi.h set.o: ../hdrs/command.h set.o: ../hdrs/switches.h -set.o: ../hdrs/ansi.h set.o: ../hdrs/mymalloc.h set.o: ../hdrs/lock.h +set.o: ../hdrs/boolexp.h set.o: ../hdrs/log.h +set.o: ../hdrs/game.h shs.o: ../hdrs/copyrite.h shs.o: ../config.h sig.o: ../config.h @@ -1558,37 +1535,53 @@ sig.o: ../hdrs/dbdefs.h sig.o: ../hdrs/mushdb.h sig.o: ../hdrs/flags.h sig.o: ../hdrs/ptab.h -sig.o: ../hdrs/division.h sig.o: ../hdrs/chunk.h -sig.o: ../hdrs/bufferq.h sig.o: ../confmagic.h +sig.o: ../hdrs/mypcre.h +sort.o: ../hdrs/copyrite.h +sort.o: ../config.h +sort.o: ../hdrs/conf.h +sort.o: ../options.h +sort.o: ../hdrs/mushtype.h +sort.o: ../hdrs/htab.h +sort.o: ../hdrs/externs.h +sort.o: ../hdrs/compile.h +sort.o: ../hdrs/dbdefs.h +sort.o: ../hdrs/mushdb.h +sort.o: ../hdrs/flags.h +sort.o: ../hdrs/ptab.h +sort.o: ../hdrs/chunk.h +sort.o: ../confmagic.h +sort.o: ../hdrs/mypcre.h +sort.o: ../hdrs/parse.h +sort.o: ../hdrs/ansi.h +sort.o: ../hdrs/command.h +sort.o: ../hdrs/switches.h +sort.o: ../hdrs/sort.h speech.o: ../hdrs/copyrite.h speech.o: ../config.h speech.o: ../hdrs/conf.h speech.o: ../options.h speech.o: ../hdrs/mushtype.h speech.o: ../hdrs/htab.h -speech.o: ../hdrs/ansi.h speech.o: ../hdrs/externs.h speech.o: ../hdrs/compile.h speech.o: ../hdrs/dbdefs.h speech.o: ../hdrs/mushdb.h speech.o: ../hdrs/flags.h speech.o: ../hdrs/ptab.h -speech.o: ../hdrs/division.h speech.o: ../hdrs/chunk.h -speech.o: ../hdrs/bufferq.h speech.o: ../confmagic.h +speech.o: ../hdrs/mypcre.h +speech.o: ../hdrs/ansi.h speech.o: ../hdrs/lock.h speech.o: ../hdrs/boolexp.h speech.o: ../hdrs/log.h speech.o: ../hdrs/match.h speech.o: ../hdrs/attrib.h -speech.o: ../hdrs/command.h -speech.o: ../hdrs/switches.h speech.o: ../hdrs/parse.h speech.o: ../hdrs/game.h -speech.o: ../hdrs/pcre.h +speech.o: ../hdrs/sort.h sql.o: ../hdrs/copyrite.h sql.o: ../config.h sql.o: ../hdrs/conf.h @@ -1601,17 +1594,15 @@ sql.o: ../hdrs/dbdefs.h sql.o: ../hdrs/mushdb.h sql.o: ../hdrs/flags.h sql.o: ../hdrs/ptab.h -sql.o: ../hdrs/division.h sql.o: ../hdrs/chunk.h -sql.o: ../hdrs/bufferq.h sql.o: ../confmagic.h -sql.o: ../hdrs/access.h +sql.o: ../hdrs/mypcre.h sql.o: ../hdrs/log.h sql.o: ../hdrs/parse.h -sql.o: ../hdrs/boolexp.h sql.o: ../hdrs/command.h sql.o: ../hdrs/switches.h sql.o: ../hdrs/function.h +sql.o: ../hdrs/ansi.h strdup.o: ../config.h strdup.o: ../hdrs/conf.h strdup.o: ../hdrs/copyrite.h @@ -1632,10 +1623,9 @@ strtree.o: ../hdrs/dbdefs.h strtree.o: ../hdrs/mushdb.h strtree.o: ../hdrs/flags.h strtree.o: ../hdrs/ptab.h -strtree.o: ../hdrs/division.h strtree.o: ../hdrs/chunk.h -strtree.o: ../hdrs/bufferq.h strtree.o: ../confmagic.h +strtree.o: ../hdrs/mypcre.h strtree.o: ../hdrs/strtree.h strutil.o: ../config.h strutil.o: ../hdrs/copyrite.h @@ -1644,7 +1634,6 @@ strutil.o: ../options.h strutil.o: ../hdrs/mushtype.h strutil.o: ../hdrs/htab.h strutil.o: ../hdrs/case.h -strutil.o: ../hdrs/ansi.h strutil.o: ../hdrs/pueblo.h strutil.o: ../hdrs/parse.h strutil.o: ../confmagic.h @@ -1654,9 +1643,9 @@ strutil.o: ../hdrs/dbdefs.h strutil.o: ../hdrs/mushdb.h strutil.o: ../hdrs/flags.h strutil.o: ../hdrs/ptab.h -strutil.o: ../hdrs/division.h strutil.o: ../hdrs/chunk.h -strutil.o: ../hdrs/bufferq.h +strutil.o: ../hdrs/mypcre.h +strutil.o: ../hdrs/ansi.h strutil.o: ../hdrs/mymalloc.h strutil.o: ../hdrs/log.h timer.o: ../hdrs/copyrite.h @@ -1671,15 +1660,11 @@ timer.o: ../hdrs/dbdefs.h timer.o: ../hdrs/mushdb.h timer.o: ../hdrs/flags.h timer.o: ../hdrs/ptab.h -timer.o: ../hdrs/division.h timer.o: ../hdrs/chunk.h -timer.o: ../hdrs/bufferq.h timer.o: ../confmagic.h -timer.o: ../hdrs/attrib.h -timer.o: ../hdrs/boolexp.h -timer.o: ../hdrs/command.h -timer.o: ../hdrs/switches.h +timer.o: ../hdrs/mypcre.h timer.o: ../hdrs/lock.h +timer.o: ../hdrs/boolexp.h timer.o: ../hdrs/extmail.h timer.o: ../hdrs/match.h timer.o: ../hdrs/access.h @@ -1687,6 +1672,7 @@ timer.o: ../hdrs/log.h timer.o: ../hdrs/game.h timer.o: ../hdrs/help.h timer.o: ../hdrs/parse.h +timer.o: ../hdrs/attrib.h unparse.o: ../hdrs/copyrite.h unparse.o: ../config.h unparse.o: ../hdrs/conf.h @@ -1699,15 +1685,12 @@ unparse.o: ../hdrs/dbdefs.h unparse.o: ../hdrs/mushdb.h unparse.o: ../hdrs/flags.h unparse.o: ../hdrs/ptab.h -unparse.o: ../hdrs/division.h unparse.o: ../hdrs/chunk.h -unparse.o: ../hdrs/bufferq.h unparse.o: ../confmagic.h +unparse.o: ../hdrs/mypcre.h unparse.o: ../hdrs/lock.h unparse.o: ../hdrs/boolexp.h unparse.o: ../hdrs/attrib.h -unparse.o: ../hdrs/command.h -unparse.o: ../hdrs/switches.h unparse.o: ../hdrs/ansi.h unparse.o: ../hdrs/pueblo.h unparse.o: ../hdrs/parse.h @@ -1724,18 +1707,16 @@ utils.o: ../hdrs/dbdefs.h utils.o: ../hdrs/mushdb.h utils.o: ../hdrs/flags.h utils.o: ../hdrs/ptab.h -utils.o: ../hdrs/division.h utils.o: ../hdrs/chunk.h -utils.o: ../hdrs/bufferq.h utils.o: ../confmagic.h +utils.o: ../hdrs/mypcre.h +utils.o: ../hdrs/ansi.h utils.o: ../hdrs/mymalloc.h utils.o: ../hdrs/log.h utils.o: ../hdrs/attrib.h -utils.o: ../hdrs/boolexp.h -utils.o: ../hdrs/command.h -utils.o: ../hdrs/switches.h utils.o: ../hdrs/parse.h utils.o: ../hdrs/lock.h +utils.o: ../hdrs/boolexp.h version.o: ../config.h version.o: ../hdrs/copyrite.h version.o: ../hdrs/conf.h @@ -1748,12 +1729,13 @@ version.o: ../hdrs/dbdefs.h version.o: ../hdrs/mushdb.h version.o: ../hdrs/flags.h version.o: ../hdrs/ptab.h -version.o: ../hdrs/division.h version.o: ../hdrs/chunk.h -version.o: ../hdrs/bufferq.h version.o: ../confmagic.h +version.o: ../hdrs/mypcre.h version.o: ../hdrs/version.h +version.o: ../hdrs/patches.h version.o: ../hdrs/buildinf.h +wait.o: ../config.h warnings.o: ../config.h warnings.o: ../hdrs/copyrite.h warnings.o: ../hdrs/conf.h @@ -1766,16 +1748,13 @@ warnings.o: ../hdrs/dbdefs.h warnings.o: ../hdrs/mushdb.h warnings.o: ../hdrs/flags.h warnings.o: ../hdrs/ptab.h -warnings.o: ../hdrs/division.h warnings.o: ../hdrs/chunk.h -warnings.o: ../hdrs/bufferq.h warnings.o: ../confmagic.h +warnings.o: ../hdrs/mypcre.h warnings.o: ../hdrs/lock.h warnings.o: ../hdrs/boolexp.h warnings.o: ../hdrs/match.h warnings.o: ../hdrs/attrib.h -warnings.o: ../hdrs/command.h -warnings.o: ../hdrs/switches.h wild.o: ../config.h wild.o: ../hdrs/copyrite.h wild.o: ../hdrs/conf.h @@ -1789,13 +1768,12 @@ wild.o: ../hdrs/dbdefs.h wild.o: ../hdrs/mushdb.h wild.o: ../hdrs/flags.h wild.o: ../hdrs/ptab.h -wild.o: ../hdrs/division.h wild.o: ../hdrs/chunk.h -wild.o: ../hdrs/bufferq.h wild.o: ../confmagic.h +wild.o: ../hdrs/mypcre.h +wild.o: ../hdrs/ansi.h wild.o: ../hdrs/mymalloc.h wild.o: ../hdrs/parse.h -wild.o: ../hdrs/pcre.h wiz.o: ../hdrs/copyrite.h wiz.o: ../config.h wiz.o: ../hdrs/conf.h @@ -1808,146 +1786,18 @@ wiz.o: ../hdrs/dbdefs.h wiz.o: ../hdrs/mushdb.h wiz.o: ../hdrs/flags.h wiz.o: ../hdrs/ptab.h -wiz.o: ../hdrs/division.h wiz.o: ../hdrs/chunk.h -wiz.o: ../hdrs/bufferq.h wiz.o: ../confmagic.h +wiz.o: ../hdrs/mypcre.h wiz.o: ../hdrs/attrib.h -wiz.o: ../hdrs/boolexp.h -wiz.o: ../hdrs/command.h -wiz.o: ../hdrs/switches.h wiz.o: ../hdrs/match.h wiz.o: ../hdrs/access.h wiz.o: ../hdrs/parse.h wiz.o: ../hdrs/mymalloc.h wiz.o: ../hdrs/lock.h +wiz.o: ../hdrs/boolexp.h wiz.o: ../hdrs/log.h wiz.o: ../hdrs/game.h +wiz.o: ../hdrs/command.h +wiz.o: ../hdrs/switches.h wiz.o: ../hdrs/extmail.h -../hdrs/atr_tab.o: ../hdrs/attrib.h -../hdrs/atr_tab.o: ../hdrs/mushtype.h -../hdrs/atr_tab.o: ../hdrs/copyrite.h -../hdrs/atr_tab.o: ../options.h -../hdrs/atr_tab.o: ../hdrs/boolexp.h -../hdrs/atr_tab.o: ../hdrs/chunk.h -../hdrs/atr_tab.o: ../hdrs/command.h -../hdrs/atr_tab.o: ../hdrs/division.h -../hdrs/atr_tab.o: ../hdrs/ptab.h -../hdrs/atr_tab.o: ../hdrs/switches.h -../hdrs/attrib.o: ../hdrs/mushtype.h -../hdrs/attrib.o: ../hdrs/copyrite.h -../hdrs/attrib.o: ../options.h -../hdrs/attrib.o: ../hdrs/boolexp.h -../hdrs/attrib.o: ../hdrs/chunk.h -../hdrs/attrib.o: ../hdrs/command.h -../hdrs/attrib.o: ../hdrs/division.h -../hdrs/attrib.o: ../hdrs/ptab.h -../hdrs/attrib.o: ../hdrs/switches.h -../hdrs/boolexp.o: ../hdrs/copyrite.h -../hdrs/boolexp.o: ../hdrs/chunk.h -../hdrs/boolexp.o: ../hdrs/mushtype.h -../hdrs/boolexp.o: ../options.h -../hdrs/case.o: ../config.h -../hdrs/case.o: ../config.h -../hdrs/chunk.o: ../hdrs/mushtype.h -../hdrs/chunk.o: ../hdrs/copyrite.h -../hdrs/chunk.o: ../options.h -../hdrs/command.o: ../hdrs/boolexp.h -../hdrs/command.o: ../hdrs/copyrite.h -../hdrs/command.o: ../hdrs/chunk.h -../hdrs/command.o: ../hdrs/mushtype.h -../hdrs/command.o: ../options.h -../hdrs/command.o: ../hdrs/division.h -../hdrs/command.o: ../hdrs/ptab.h -../hdrs/command.o: ../hdrs/switches.h -../hdrs/conf.o: ../hdrs/copyrite.h -../hdrs/conf.o: ../options.h -../hdrs/conf.o: ../hdrs/mushtype.h -../hdrs/conf.o: ../hdrs/htab.h -../hdrs/dbdefs.o: ../hdrs/mushdb.h -../hdrs/dbdefs.o: ../config.h -../hdrs/dbdefs.o: ../hdrs/copyrite.h -../hdrs/dbdefs.o: ../hdrs/flags.h -../hdrs/dbdefs.o: ../hdrs/mushtype.h -../hdrs/dbdefs.o: ../options.h -../hdrs/dbdefs.o: ../hdrs/ptab.h -../hdrs/dbdefs.o: ../hdrs/division.h -../hdrs/dbdefs.o: ../hdrs/htab.h -../hdrs/dbdefs.o: ../hdrs/chunk.h -../hdrs/dbdefs.o: ../hdrs/bufferq.h -../hdrs/externs.o: ../config.h -../hdrs/externs.o: ../hdrs/copyrite.h -../hdrs/externs.o: ../hdrs/compile.h -../hdrs/externs.o: ../hdrs/mushtype.h -../hdrs/externs.o: ../options.h -../hdrs/externs.o: ../hdrs/dbdefs.h -../hdrs/externs.o: ../hdrs/mushdb.h -../hdrs/externs.o: ../hdrs/flags.h -../hdrs/externs.o: ../hdrs/ptab.h -../hdrs/externs.o: ../hdrs/division.h -../hdrs/externs.o: ../hdrs/htab.h -../hdrs/externs.o: ../hdrs/chunk.h -../hdrs/externs.o: ../hdrs/bufferq.h -../hdrs/externs.o: ../confmagic.h -../hdrs/flags.o: ../hdrs/mushtype.h -../hdrs/flags.o: ../hdrs/copyrite.h -../hdrs/flags.o: ../options.h -../hdrs/flags.o: ../hdrs/ptab.h -../hdrs/flags.o: ../hdrs/division.h -../hdrs/function.o: ../hdrs/copyrite.h -../hdrs/function.o: ../hdrs/boolexp.h -../hdrs/function.o: ../hdrs/chunk.h -../hdrs/function.o: ../hdrs/mushtype.h -../hdrs/function.o: ../options.h -../hdrs/ident.o: ../config.h -../hdrs/ident.o: ../hdrs/mysocket.h -../hdrs/ident.o: ../hdrs/copyrite.h -../hdrs/ident.o: ../confmagic.h -../hdrs/lock.o: ../hdrs/copyrite.h -../hdrs/lock.o: ../hdrs/mushtype.h -../hdrs/lock.o: ../options.h -../hdrs/lock.o: ../hdrs/conf.h -../hdrs/lock.o: ../hdrs/htab.h -../hdrs/lock.o: ../hdrs/boolexp.h -../hdrs/lock.o: ../hdrs/chunk.h -../hdrs/match.o: ../hdrs/copyrite.h -../hdrs/mushdb.o: ../config.h -../hdrs/mushdb.o: ../hdrs/copyrite.h -../hdrs/mushdb.o: ../hdrs/flags.h -../hdrs/mushdb.o: ../hdrs/mushtype.h -../hdrs/mushdb.o: ../options.h -../hdrs/mushdb.o: ../hdrs/ptab.h -../hdrs/mushdb.o: ../hdrs/division.h -../hdrs/mushtype.o: ../hdrs/copyrite.h -../hdrs/mushtype.o: ../options.h -../hdrs/mymalloc.o: ../options.h -../hdrs/mysocket.o: ../hdrs/copyrite.h -../hdrs/mysocket.o: ../config.h -../hdrs/mysocket.o: ../confmagic.h -../hdrs/myssl.o: ../hdrs/copyrite.h -../hdrs/parse.o: ../hdrs/copyrite.h -../hdrs/parse.o: ../config.h -../hdrs/parse.o: ../confmagic.h -../hdrs/privtab.o: ../hdrs/copyrite.h -../hdrs/privtab.o: ../config.h -../hdrs/privtab.o: ../confmagic.h -../hdrs/division.o: ../hdrs/ptab.h -../hdrs/cron.o: ../hdrs/conf.h -../hdrs/cron.o: ../hdrs/copyrite.h -../hdrs/cron.o: ../options.h -../hdrs/cron.o: ../hdrs/mushtype.h -../hdrs/cron.o: ../hdrs/htab.h -../hdrs/cron.o: ../hdrs/externs.h -../hdrs/cron.o: ../config.h -../hdrs/cron.o: ../hdrs/compile.h -../hdrs/cron.o: ../hdrs/dbdefs.h -../hdrs/cron.o: ../hdrs/mushdb.h -../hdrs/cron.o: ../hdrs/flags.h -../hdrs/cron.o: ../hdrs/ptab.h -../hdrs/cron.o: ../hdrs/division.h -../hdrs/cron.o: ../hdrs/chunk.h -../hdrs/cron.o: ../hdrs/bufferq.h -../hdrs/cron.o: ../confmagic.h -../hdrs/cron.o: ../hdrs/command.h -../hdrs/cron.o: ../hdrs/boolexp.h -../hdrs/cron.o: ../hdrs/switches.h diff --git a/src/SWITCHES b/src/SWITCHES index e99dcd4..63214d2 100644 --- a/src/SWITCHES +++ b/src/SWITCHES @@ -12,6 +12,7 @@ BEFORE BLIND BRIEF BUFFER +BUILTIN CHECK CHOWN CHUNKS diff --git a/src/access.c b/src/access.c index c78a1f2..cc7103c 100644 --- a/src/access.c +++ b/src/access.c @@ -59,6 +59,7 @@ #include #include #include +#include #include #ifdef I_SYS_TYPES #include @@ -66,6 +67,9 @@ #include #ifdef I_SYS_TIME #include +#ifdef TIME_WITH_SYS_TIME +#include +#endif #else #include #endif @@ -74,6 +78,7 @@ #endif #include "conf.h" #include "externs.h" +#include "mypcre.h" #include "access.h" #include "mymalloc.h" #include "match.h" @@ -84,7 +89,6 @@ #include "flags.h" #include "confmagic.h" - /** An access flag. */ typedef struct a_acsflag acsflag; /** An access flag. @@ -92,8 +96,8 @@ typedef struct a_acsflag acsflag; */ struct a_acsflag { const char *name; /**< Name of the access flag */ - int toggle; /**< Is this a negatable flag? */ - int flag; /**< Bitmask of the flag */ + bool toggle; /**< Is this a negatable flag? */ + uint32_t flag; /**< Bitmask of the flag */ }; static acsflag acslist[] = { {"connect", 1, ACS_CONNECT}, @@ -111,31 +115,73 @@ static acsflag acslist[] = { }; static struct access *access_top; -static int add_access_node - (const char *host, const dbref who, const int can, const int cant, - const char *comment); static void free_access_list(void); -static int -add_access_node(const char *host, const dbref who, const int can, - const int cant, const char *comment) +extern const unsigned char *tables; + +static void +sitelock_free(struct access *ap) { - struct access *end; - struct access *tmp; + mush_free(ap->host, "sitelock.rule.host"); + if (ap->comment) + mush_free(ap->comment, "sitelock.rule.comment"); + if (ap->re) + free(ap); + mush_free(ap, "sitelock.rule"); +} - tmp = (struct access *) mush_malloc(sizeof(struct access), "struct_access"); - if (!tmp) - return 0; +static struct access * +sitelock_alloc(const char *host, dbref who, + uint32_t can, uint32_t cant, + const char *comment, const char **errptr) + __attribute_malloc__; + + static struct access *sitelock_alloc(const char *host, dbref who, + uint32_t can, uint32_t cant, + const char *comment, + const char **errptr) +{ + struct access *tmp; + tmp = mush_malloc(sizeof(struct access), "sitelock.rule"); + if (!tmp) { + static const char *memerr = "unable to allocate memory"; + if (errptr) + *errptr = memerr; + return NULL; + } tmp->who = who; tmp->can = can; tmp->cant = cant; - strcpy(tmp->host, host); - if (comment) - strcpy(tmp->comment, comment); + tmp->host = mush_strdup(host, "sitelock.rule.host"); + if (comment && *comment) + tmp->comment = mush_strdup(comment, "sitelock.rule.comment"); else - tmp->comment[0] = '\0'; + tmp->comment = NULL; tmp->next = NULL; + if (can & ACS_REGEXP) { + int erroffset = 0; + tmp->re = pcre_compile(host, 0, errptr, &erroffset, tables); + if (!tmp->re) { + sitelock_free(tmp); + return NULL; + } + } else + tmp->re = NULL; + + return tmp; +} + +static bool +add_access_node(const char *host, dbref who, uint32_t can, + uint32_t cant, const char *comment, const char **errptr) +{ + struct access *end, *tmp; + + tmp = sitelock_alloc(host, who, can, cant, comment, errptr); + if (!tmp) + return false; + if (!access_top) { /* Add to the beginning */ access_top = tmp; @@ -145,25 +191,25 @@ add_access_node(const char *host, const dbref who, const int can, end = end->next; end->next = tmp; } - - return 1; + return true; } /** Read the access.cnf file. * Initialize the access rules linked list and read in the access.cnf file. - * Return 1 if successful, 0 if not + * \return true if successful, false if not */ -int +bool read_access_file(void) { FILE *fp; char buf[BUFFER_LEN]; char *p; - int can, cant; + uint32_t can, cant; int retval; dbref who; char *comment; + const char *errptr = NULL; if (access_top) { /* We're reloading the file, so we've got to delete any current @@ -176,7 +222,7 @@ read_access_file(void) release_fd(); fp = fopen(ACCESS_FILE, FOPEN_READ); if (!fp) { - do_log(LT_ERR, GOD, GOD, T("No %s file found."), ACCESS_FILE); + do_rawlog(LT_ERR, T("Access file %s not found."), ACCESS_FILE); retval = 0; } else { do_rawlog(LT_ERR, "Reading %s", ACCESS_FILE); @@ -195,8 +241,10 @@ read_access_file(void) comment = NULL; /* Is this the @sitelock entry? */ if (!strncasecmp(p, "@sitelock", 9)) { - if (!add_access_node("@sitelock", AMBIGUOUS, ACS_SITELOCK, 0, "")) - do_log(LT_ERR, GOD, GOD, T("Failed to add sitelock node!")); + if (!add_access_node("@sitelock", AMBIGUOUS, ACS_SITELOCK, 0, "", + &errptr)) + do_log(LT_ERR, GOD, GOD, T("Failed to add sitelock node: %s"), + errptr); } else { if ((comment = strchr(p, '#'))) { *comment++ = '\0'; @@ -211,8 +259,9 @@ read_access_file(void) if (!parse_access_options(p, &who, &can, &cant, NOTHING)) /* Nothing listed, so assume we can't do anything! */ cant = ACS_DEFAULT; - if (!add_access_node(buf, who, can, cant, comment)) - do_log(LT_ERR, GOD, GOD, T("Failed to add access node!")); + if (!add_access_node(buf, who, can, cant, comment, &errptr)) + do_log(LT_ERR, GOD, GOD, T("Failed to add access node: %s"), + errptr); } } } @@ -234,7 +283,7 @@ write_access_file(void) struct access *ap; acsflag *c; - sprintf(tmpf, "%s.tmp", ACCESS_FILE); + snprintf(tmpf, BUFFER_LEN, "%s.tmp", ACCESS_FILE); /* Be sure we have a file descriptor */ release_fd(); fp = fopen(tmpf, FOPEN_WRITE); @@ -269,10 +318,10 @@ write_access_file(void) fprintf(fp, "!%s ", c->name); break; } - if (ap->comment && *ap->comment) + if (ap->comment) fprintf(fp, "# %s\n", ap->comment); else - fprintf(fp, "\n"); + fputc('\n', fp); } fclose(fp); #ifdef WIN32 @@ -316,12 +365,12 @@ ip4_to_ip6(const char *addr) * flags (can't register, isn't suspect) * \endverbatim */ -int -site_can_access(const char *hname, int flag, dbref who) +bool +site_can_access(const char *hname, uint32_t flag, dbref who) { struct access *ap; acsflag *c; - char *p; + const char *p; if (!hname || !*hname) return 0; @@ -330,22 +379,13 @@ site_can_access(const char *hname, int flag, dbref who) p++; for (ap = access_top; ap; ap = ap->next) { - if (!(ap->can & ACS_SITELOCK) - && ((ap->can & ACS_REGEXP) - ? (quick_regexp_match(ap->host, hname, 0) - || (p && quick_regexp_match(ap->host, p, 0)) -#ifdef FORCE_IPV4 - || quick_regexp_match(ip4_to_ip6(ap->host), hname, 0) - || (p && quick_regexp_match(ip4_to_ip6(ap->host), p, 0)) -#endif - ) - : (quick_wild(ap->host, hname) - || (p && quick_wild(ap->host, p)) -#ifdef FORCE_IPV4 - || quick_wild(ip4_to_ip6(ap->host), hname) - || (p && quick_wild(ip4_to_ip6(ap->host), p)) -#endif - )) + if (ap->can & ACS_SITELOCK) + continue; + if ((ap->can & ACS_REGEXP) + ? (qcomp_regexp_match(ap->re, hname) + || (p && qcomp_regexp_match(ap->re, p))) + : (quick_wild(ap->host, hname) + || (p && quick_wild(ap->host, p))) && (ap->who == AMBIGUOUS || ap->who == who)) { /* Got one */ if (flag & ACS_CONNECT) { @@ -389,7 +429,7 @@ struct access * site_check_access(const char *hname, dbref who, int *rulenum) { struct access *ap; - char *p; + const char *p; *rulenum = 0; if (!hname || !*hname) @@ -400,22 +440,13 @@ site_check_access(const char *hname, dbref who, int *rulenum) for (ap = access_top; ap; ap = ap->next) { (*rulenum)++; - if (!(ap->can & ACS_SITELOCK) - && ((ap->can & ACS_REGEXP) - ? (quick_regexp_match(ap->host, hname, 0) - || (p && quick_regexp_match(ap->host, p, 0)) -#ifdef FORCE_IPV4 - || quick_regexp_match(ip4_to_ip6(ap->host), hname, 0) - || (p && quick_regexp_match(ip4_to_ip6(ap->host), p, 0)) -#endif - ) - : (quick_wild(ap->host, hname) - || (p && quick_wild(ap->host, p)) -#ifdef FORCE_IPV4 - || quick_wild(ip4_to_ip6(ap->host), hname) - || (p && quick_wild(ip4_to_ip6(ap->host), p)) -#endif - )) + if (ap->can & ACS_SITELOCK) + continue; + if (((ap->can & ACS_REGEXP) + ? (qcomp_regexp_match(ap->re, hname) + || (p && qcomp_regexp_match(ap->re, p))) + : (quick_wild(ap->host, hname) + || (p && quick_wild(ap->host, p)))) && (ap->who == AMBIGUOUS || ap->who == who)) { /* Got one */ return ap; @@ -433,7 +464,7 @@ site_check_access(const char *hname, dbref who, int *rulenum) * This function provides an appealing display of an access rule * in the list. */ -int +void format_access(struct access *ap, int rulenum, dbref who __attribute__ ((__unused__)), char *buff, char **bp) { @@ -474,7 +505,6 @@ format_access(struct access *ap, int rulenum, } else { safe_str(T("No matching access rule"), buff, bp); } - return 0; } @@ -493,29 +523,28 @@ format_access(struct access *ap, int rulenum, * Build an appropriate comment based on the player and date * \endverbatim */ -int -add_access_sitelock(dbref player, const char *host, dbref who, int can, - int cant) +bool +add_access_sitelock(dbref player, const char *host, dbref who, uint32_t can, + uint32_t cant) { struct access *end; struct access *tmp; + const char *errptr = NULL; - tmp = (struct access *) mush_malloc(sizeof(struct access), "struct_access"); - if (!tmp) - return 0; - tmp->who = who; - tmp->can = can; - tmp->cant = cant; - strcpy(tmp->host, host); - sprintf(tmp->comment, "By %s(#%d) on %s", Name(player), player, - show_time(mudtime, 0)); - tmp->next = NULL; + tmp = sitelock_alloc(host, who, can, cant, "", &errptr); + + if (!tmp) { + notify_format(player, T("Unable to add sitelock entry: %s"), errptr); + return false; + } if (!access_top) { /* Add to the beginning, but first add a sitelock marker */ - if (!add_access_node("@sitelock", AMBIGUOUS, ACS_SITELOCK, 0, "")) + if (!add_access_node("@sitelock", AMBIGUOUS, ACS_SITELOCK, 0, "", &errptr)) { + notify_format(player, T("Unable to add @sitelock separator: %s"), errptr); return 0; + } access_top->next = tmp; } else { end = access_top; @@ -524,8 +553,12 @@ add_access_sitelock(dbref player, const char *host, dbref who, int can, /* Now, either we're at the sitelock or the end */ if (end->can != ACS_SITELOCK) { /* We're at the end and there's no sitelock marker. Add one */ - if (!add_access_node("@sitelock", AMBIGUOUS, ACS_SITELOCK, 0, "")) + if (!add_access_node("@sitelock", AMBIGUOUS, ACS_SITELOCK, 0, "", + &errptr)) { + notify_format(player, T("Unable to add @sitelock separator: %s"), + errptr); return 0; + } end = end->next; } else { /* We're in the middle, so be sure we keep the list linked */ @@ -539,35 +572,43 @@ add_access_sitelock(dbref player, const char *host, dbref who, int can, /** Remove an access rule from the linked list. * \param pattern access rule host pattern to match. * \return number of rule removed. - * \verbatim * This function removes an access rule from the list. * Only rules that appear after the "@sitelock" rule can be * removed with this function. - * \endverbatim */ int remove_access_sitelock(const char *pattern) { struct access *ap, *next, *prev = NULL; int n = 0; + int rulenum = 0, deletethis = -1; + + if (is_strict_integer(pattern)) + deletethis = parse_integer(pattern); /* We only want to be able to delete entries added with @sitelock */ - for (ap = access_top; ap; ap = ap->next) + for (ap = access_top; ap; ap = ap->next) { + rulenum++; if (strcmp(ap->host, "@sitelock") == 0) { prev = ap; ap = ap->next; break; } + } while (ap) { + rulenum++; next = ap->next; - if (strcasecmp(pattern, ap->host) == 0) { + if (deletethis == -1 ? (strcasecmp(pattern, ap->host) == 0) + : deletethis == rulenum) { n++; - mush_free(ap, "struct_access"); + sitelock_free(ap); if (prev) prev->next = next; else access_top = next; + if (deletethis >= 0) + break; } else { prev = ap; } @@ -585,7 +626,7 @@ free_access_list() ap = access_top; while (ap) { next = ap->next; - mush_free((Malloc_t) ap, "struct_access"); + sitelock_free(ap); ap = next; } access_top = NULL; @@ -626,7 +667,7 @@ do_list_access(dbref player) notify_format(player, "%3d SITE: %-20s DBREF: %-6s FLAGS:%s", rulenum, ap->host, unparse_dbref(ap->who), flaglist); - notify_format(player, " COMMENT: %s", ap->comment); + notify_format(player, " COMMENT: %s", ap->comment ? ap->comment : ""); } else { notify(player, T @@ -634,6 +675,9 @@ do_list_access(dbref player) } } + if (rulenum == 0) { + notify(player, T("There are no access rules.")); + } } /** Parse access options into fields. @@ -648,8 +692,8 @@ do_list_access(dbref player) * This makes a copy of the options string, so it's not modified. */ int -parse_access_options(const char *opts, dbref *who, int *can, int *cant, - dbref player) +parse_access_options(const char *opts, dbref *who, uint32_t * can, + uint32_t * cant, dbref player) { char myopts[BUFFER_LEN]; char *p; diff --git a/src/atr_tab.c b/src/atr_tab.c index ec5612a..036c900 100644 --- a/src/atr_tab.c +++ b/src/atr_tab.c @@ -8,9 +8,13 @@ #include "config.h" +#include #include #include #include +#ifdef I_SYS_TYPES +#include +#endif #include "conf.h" #include "externs.h" #include "attrib.h" @@ -86,7 +90,7 @@ PRIV attr_privs_view[] = { {"nearby", 'n', AF_NEARBY, AF_NEARBY}, {"amhear", 'M', AF_MHEAR, AF_MHEAR}, {"aahear", 'A', AF_AHEAR, AF_AHEAR}, - {"root", '`', AF_ROOT, AF_ROOT}, + {"", '`', AF_ROOT, AF_ROOT}, {NULL, '\0', 0, 0} }; @@ -145,9 +149,7 @@ alias_attribute(const char *atr, const char *alias) if (!ap) return 0; - ptab_start_inserts(&ptab_attrib); - ptab_insert(&ptab_attrib, strupper(alias), ap); - ptab_end_inserts(&ptab_attrib); + ptab_insert_one(&ptab_attrib, strupper(alias), ap); return 1; } @@ -282,7 +284,7 @@ void do_attribute_access(dbref player, char *name, char *perms, int retroactive) { ATTR *ap, *ap2; - int flags = 0; + privbits flags = 0; int i; int insert = 0; @@ -291,7 +293,7 @@ do_attribute_access(dbref player, char *name, char *perms, int retroactive) notify(player, T("Which attribute do you mean?")); return; } - if (strcasecmp(perms, "none")) { + if(strcasecmp(perms, "none")) { flags = list_to_privs(attr_privs_set, perms, 0); if (!flags) { notify(player, T("I don't understand those permissions.")); @@ -335,9 +337,7 @@ do_attribute_access(dbref player, char *name, char *perms, int retroactive) /* Only insert when it's not already in the table */ if (insert) { - ptab_start_inserts(&ptab_attrib); - ptab_insert(&ptab_attrib, name, ap); - ptab_end_inserts(&ptab_attrib); + ptab_insert_one(&ptab_attrib, name, ap); } /* Ok, now we need to see if there are any attributes of this name @@ -452,9 +452,7 @@ do_attribute_rename(dbref player, char *old, char *newname) added via /access. But that doesn't happen often. Will fix someday. */ AL_NAME(ap) = strdup(newname); - ptab_start_inserts(&ptab_attrib); - ptab_insert(&ptab_attrib, newname, ap); - ptab_end_inserts(&ptab_attrib); + ptab_insert_one(&ptab_attrib, newname, ap); notify_format(player, T("Renamed %s to %s in attribute table."), old, newname); return; @@ -520,7 +518,7 @@ void do_list_attribs(dbref player, int lc) { char *b = list_attribs(); - notify_format(player, "Attribs: %s", lc ? strlower(b) : b); + notify_format(player, T("Attribs: %s"), lc ? strlower(b) : b); } /** Return a list of standard attributes. diff --git a/src/attrib.c b/src/attrib.c index e6435fd..d2109c1 100644 --- a/src/attrib.c +++ b/src/attrib.c @@ -52,10 +52,6 @@ extern PRIV attr_privs_set[]; extern PRIV attr_privs_view[]; dbref atr_on_obj = NOTHING; -static int real_atr_clr(dbref thinking, char const *atr, dbref player, - int we_are_wiping); - - dbref global_parent_depth[] = { 0, 0 }; /** A string to hold the name of a missing prefix branch, set by @@ -68,24 +64,17 @@ static char missing_name[ATTRIBUTE_NAME_LIMIT + 1]; /** 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 atr_clear_children(dbref player, dbref thing, ATTR *root); -static ATTR *atr_free_list = NULL; -static ATTR *alloc_atr(void); -static ATTR *pop_free_list(void); -static void push_free_list(ATTR *); static void atr_free_one(ATTR *); +static int real_atr_clr(dbref thinking, char const *atr, dbref player, + int we_are_wiping); +static ATTR *alloc_atr(const void *hint); +static void free_atr(ATTR *); static ATTR *find_atr_pos_in_list(ATTR *** pos, char const *name); -static atr_err can_create_attr(dbref player, dbref obj, char const *atr_name, - unsigned int flags); +static int can_create_attr(dbref player, dbref obj, char const *atr_name, + uint32_t flags); static int can_create_attr(dbref player, dbref obj, char const *atr_name, unsigned int flags); static ATTR *find_atr_in_list(ATTR * atr, char const *name); @@ -135,7 +124,7 @@ static ATTR *find_atr_in_list(ATTR * atr, char const *name); * lock_owner - lock owner **/ -int cannot_write_this_attr_internal(dbref player, ATTR *attr, dbref obj, char safe, char ns_chk, dbref lowner) { +int cannot_write_this_attr_internal(dbref player, ATTR *attr, dbref obj, char safe __attribute__ ((__unused__)), char ns_chk, dbref lowner) { dbref lock_owner; if(!GoodObject(lowner)) @@ -266,7 +255,7 @@ find_atr_in_list(ATTR * atr, char const *name) return NULL; } -/** Find the place to insert an attribute with the specified name. +/** Find the place to insert/delete an attribute with the specified name. * \param pos a pointer to the ATTR ** holding the list position * \param name the attribute name to look for * \return the matching attribute, or NULL if no matching attribute @@ -294,12 +283,13 @@ find_atr_pos_in_list(ATTR *** pos, char const *name) * all of those flags. * \param player the dbref to use for privilege checks. * \param p a space-separated string of attribute flags. - * \return an attribute flag bitmask. + * \param bits pointer to a privbits to store the attribute flags mask. + * \return 0 on success, -1 on error */ int -string_to_atrflag(dbref player, char const *p) +string_to_atrflag(dbref player, char const *p, privbits *bits) { - int f; + privbits f; f = string_to_privs(attr_privs_set, p, 0); if (!f) return -1; @@ -308,7 +298,8 @@ string_to_atrflag(dbref player, char const *p) if (!div_powover(player, player, "Privilege") && (f & AF_PRIVILEGE)) return -1; f &= ~AF_INTERNAL; - return f; + *bits = f; + return 0; } /** Convert a string of attribute flags to a pair of bitmasks. @@ -319,10 +310,11 @@ string_to_atrflag(dbref player, char const *p) * \param p a space-separated string of attribute flags. * \param setbits pointer to address of bitmask to set. * \param clrbits pointer to address of bitmask to clear. - * \return setbits or -1 on error. + * \return 0 on success or -1 on error. */ int -string_to_atrflagsets(dbref player, char const *p, int *setbits, int *clrbits) +string_to_atrflagsets(dbref player, char const *p, privbits *setbits, + privbits *clrbits) { int f; *setbits = *clrbits = 0; @@ -333,8 +325,7 @@ string_to_atrflagsets(dbref player, char const *p, int *setbits, int *clrbits) return -1; if (!See_All(player) && ((*setbits & AF_PRIVILEGE) || (*clrbits & AF_PRIVILEGE))) return -1; - f &= ~AF_INTERNAL; - return *setbits; + return 0; } /** Convert an attribute flag bitmask into a list of the full @@ -343,11 +334,29 @@ string_to_atrflagsets(dbref player, char const *p, int *setbits, int *clrbits) * \return a pointer to a static buffer with the full names of the flags. */ const char * -atrflag_to_string(int mask) +atrflag_to_string(privbits mask) { return privs_to_string(attr_privs_view, mask); } +/** If the attribute exists on the object, see if the player can modify it. + * Otherwise, see if they can create it. + * \param player the player trying to set the attr + * \param thing the object to check + * \param attrname the name of the attribute to check + * \retval 0 attribute cannot be changed by player + * \retval 1 attribute can be changed by player + */ +bool +can_edit_attr(dbref player, dbref thing, const char *attrname) +{ + ATTR *ptr = find_atr_in_list(List(thing), attrname); + if (ptr) + return Can_Write_Attr(player, thing, ptr); + else + return can_create_attr(player, thing, attrname, 0) == AE_OKAY; +} + /** Utility define for atr_add and can_create_attr */ #define set_default_flags(atr,flags, lock_owner, ns_chk) \ do { \ @@ -379,13 +388,11 @@ atrflag_to_string(int mask) * \param obj the object targetted for the write. * \param atr the attribute being interrogated. * \param flags the default flags to add to the attribute. - * 0 for default flags if it's a builtin attribute. * \retval 0 if the player cannot write the attribute. * \retval 1 if the player can write the attribute. */ static int -can_create_attr(dbref player, dbref obj, char const *atr_name, - unsigned int flags) +can_create_attr(dbref player, dbref obj, char const *atr_name, uint32_t flags) { char *p; ATTR tmpatr, *atr; @@ -398,7 +405,8 @@ can_create_attr(dbref player, dbref obj, char const *atr_name, AL_CREATOR(atr) = ooref != NOTHING ? ooref : player; AL_NAME(atr) = atr_name; - set_default_flags(atr, flags, lock_owner, ns_chk); + set_default_flags(atr, flags, lock_owner, ns_chk); /* this mallocs WLock & RLock as well */ + if(lock_owner == NOTHING) lock_owner = AL_CREATOR(atr); @@ -431,17 +439,18 @@ can_create_attr(dbref player, dbref obj, char const *atr_name, */ if ((AL_FLAGS(atr) & AF_NODUMP) && (player != GOD)) { missing_name[0] = '\0'; + free_atr_locks(atr); return AE_ERROR; } if (Cannot_Write_This_Attr(player, atr, obj, 1, ns_chk, lock_owner)) { - free_atr_locks(atr); missing_name[0] = '\0'; + free_atr_locks(atr); return AE_ERROR; } - free_atr_locks(atr); *p = '`'; } + if ((AttrCount(obj) + num_new) > (Many_Attribs(obj) ? HARD_MAX_ATTRCOUNT : MAX_ATTRCOUNT)) { do_log(LT_ERR, player, obj, @@ -461,7 +470,7 @@ can_create_attr(dbref player, dbref obj, char const *atr_name, * \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; @@ -472,7 +481,7 @@ create_atr(dbref thing, char const *atr_name) 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; @@ -509,7 +518,7 @@ create_atr(dbref thing, char const *atr_name) */ void atr_new_add(dbref thing, const char *RESTRICT atr, const char *RESTRICT s, - dbref player, unsigned int flags, unsigned char derefs, boolexp wlock, + dbref player, uint32_t flags, uint8_t derefs, boolexp wlock, boolexp rlock, time_t modtime) { ATTR *ptr; @@ -518,7 +527,7 @@ atr_new_add(dbref thing, const char *RESTRICT atr, const char *RESTRICT s, int ns_chk; char *p, root_name[ATTRIBUTE_NAME_LIMIT + 1]; - if (!EMPTY_ATTRS && !*s) + if (!EMPTY_ATTRS && !*s && !(flags & AF_ROOT)) return; /* Don't fail on a bad name, but do log it */ @@ -526,7 +535,8 @@ atr_new_add(dbref thing, const char *RESTRICT atr, const char *RESTRICT s, 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; @@ -544,8 +554,8 @@ atr_new_add(dbref thing, const char *RESTRICT atr, const char *RESTRICT s, if (!root) { do_rawlog(LT_ERR, T("Missing root attribute '%s' on object #%d!\n"), root_name, thing); - root = create_atr(thing, root_name); - set_default_flags(root, 0, lock_owner, ns_chk); + root = create_atr(thing, root_name, ptr); + set_default_flags(root, 0, lock_owner, ns_chk); /* This mallocs space in w & rlocks */ if(lock_owner == NOTHING) lock_owner = player; AL_FLAGS(root) |= AF_ROOT; @@ -559,7 +569,7 @@ atr_new_add(dbref thing, const char *RESTRICT atr, const char *RESTRICT s, free(t); } } else { - if (!AL_FLAGS(root) & AF_ROOT) /* Upgrading old database */ + if (!(AL_FLAGS(root) & AF_ROOT)) /* Upgrading old database */ AL_FLAGS(root) |= AF_ROOT; } } @@ -605,7 +615,7 @@ atr_new_add(dbref thing, const char *RESTRICT atr, const char *RESTRICT s, atr_err atr_add(dbref thing, const char *RESTRICT atr, const char *RESTRICT s, - dbref player, unsigned int flags) + dbref player, uint32_t flags) { ATTR *ptr, *root = NULL; dbref lock_owner; /* Not used.. but set in set_default_flags */ @@ -655,7 +665,7 @@ atr_add(dbref thing, const char *RESTRICT atr, const char *RESTRICT s, 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) { ooref = tooref; return AE_TREE; @@ -690,7 +700,7 @@ atr_add(dbref thing, const char *RESTRICT atr, const char *RESTRICT s, *p = '`'; } - ptr = create_atr(thing, atr); + ptr = create_atr(thing, atr, root ? root : List(thing)); if (!ptr) { ooref = tooref; return AE_ERROR; @@ -736,7 +746,7 @@ atr_add(dbref thing, const char *RESTRICT atr, const char *RESTRICT s, } ooref = tooref; - return 1; + return AE_OKAY; } /** Remove an attribute from an object. @@ -986,7 +996,7 @@ atr_iter_get(dbref player, dbref thing, const char *name, int mortal, { ATTR *ptr, **indirect; int result; - int len; + size_t len; result = 0; if (!name || !*name) @@ -1039,7 +1049,11 @@ atr_free_all(dbref thing) while ((ptr = List(thing))) { List(thing) = AL_NEXT(ptr); - atr_free_one(ptr); + if (ptr->data) + chunk_delete(ptr->data); + st_delete(AL_NAME(ptr), &atr_names); + + free_atr(ptr); } } @@ -1065,7 +1079,6 @@ atr_cpy(dbref dest, dbref source) atr_new_add(dest, AL_NAME(ptr), atr_value(ptr), AL_CREATOR(ptr), AL_FLAGS(ptr), AL_DEREFS(ptr), AL_WLock(ptr), AL_RLock(ptr), AL_MODTIME(ptr)); - AttrCount(dest)++; } } @@ -1118,7 +1131,7 @@ find_attr(UsedAttr *** prev, char const *name) * the one inserted. */ static UsedAttr ** -use_attr(UsedAttr ** prev, char const *name, int no_prog) +use_attr(UsedAttr ** prev, char const *name, uint32_t no_prog) { int found; UsedAttr *used; @@ -1162,7 +1175,7 @@ atr_comm_match(dbref thing, dbref player, int type, int end, char const *str, int just_match, char *atrname, char **abp, dbref * errobj) { - int flag_mask; + uint32_t flag_mask; ATTR *ptr; int parent_depth; char tbuf1[BUFFER_LEN]; @@ -1175,7 +1188,7 @@ atr_comm_match(dbref thing, dbref player, int type, int end, int skipcount; int lock_checked = 0; char match_space[BUFFER_LEN * 2]; - int match_space_len = BUFFER_LEN * 2; + ssize_t match_space_len = BUFFER_LEN * 2; dbref local_ooref; /* check for lots of easy ways out */ @@ -1462,7 +1475,7 @@ atr_comm_divmatch(dbref thing, dbref player, int type, int end, int skipcount; int lock_checked = 0; char match_space[BUFFER_LEN * 2]; - int match_space_len = BUFFER_LEN * 2; + ssize_t match_space_len = BUFFER_LEN * 2; /* check for lots of easy ways out */ if ((type != '$' && type != '^') || !GoodObject(thing) || Halted(thing) @@ -1817,7 +1830,7 @@ one_comm_match(dbref thing, dbref player, const char *atr, const char *str) */ int do_set_atr(dbref thing, const char *RESTRICT atr, const char *RESTRICT s, - dbref player, unsigned int flags) + dbref player, uint32_t flags) { ATTR *old; char name[BUFFER_LEN]; @@ -1923,9 +1936,7 @@ do_set_atr(dbref thing, const char *RESTRICT atr, const char *RESTRICT s, was_hearer = Hearer(thing); was_listener = Listener(thing); - res = - s ? atr_add(thing, name, s, player, - (flags & 0x02) ? AF_NOPROG : AF_EMPTY_FLAGS) + res = s ? atr_add(thing, name, s, player, (flags & 0x02) ? AF_NOPROG : 0) : atr_clr(thing, name, player); switch (res) { case AE_SAFE: @@ -1944,7 +1955,7 @@ do_set_atr(dbref thing, const char *RESTRICT atr, const char *RESTRICT s, return 0; } case AE_BADNAME: - notify_format(player, T("That's not a very good name for an attribute.")); + notify(player, T("That's not a very good name for an attribute.")); return 0; case AE_ERROR: if (*missing_name) { @@ -2010,11 +2021,11 @@ do_set_atr(dbref thing, const char *RESTRICT atr, const char *RESTRICT s, * \param arg2 the desired lock status ('on' or 'off'). */ void -do_atrlock(dbref player, const char *arg1, const char *arg2, +do_atrlock(dbref player, const char *xarg1, const char *arg2, char write_lock) { dbref thing, creator; - char *p; + char *p, *arg1; ATTR *ptr; int status; boolexp key; @@ -2022,19 +2033,25 @@ do_atrlock(dbref player, const char *arg1, const char *arg2, if (!arg2 || !*arg2) status = 0; - if (!arg1 || !*arg1) { + if (!xarg1 || !*xarg1) { notify(player, T("You need to give an object/attribute pair.")); return; } + + arg1 = mush_strdup(xarg1, "atrlock.string"); + if (!(p = strchr(arg1, '/')) || !(*(p + 1))) { notify(player, T("You need to give an object/attribute pair.")); + mush_free(arg1, "atrlock.string"); return; } *p++ = '\0'; if ((thing = noisy_match_result(player, arg1, NOTYPE, MAT_EVERYTHING)) == - NOTHING) + NOTHING) { + mush_free(arg1, "atrlock.string"); return; + } if (!controls(player, thing)) { notify(player, T("Permission denied.")); @@ -2047,6 +2064,7 @@ do_atrlock(dbref player, const char *arg1, const char *arg2, notify(player, T ("You need to be able to set the attribute to change its lock.")); + mush_free(arg1, "atrlock.string"); return; } else { creator = ooref != NOTHING ? Owner(ooref) : Owner(player); @@ -2089,6 +2107,7 @@ do_atrlock(dbref player, const char *arg1, const char *arg2, } } else notify(player, T("No such attribute.")); + mush_free(arg1, "atrlock.string"); return; } @@ -2101,35 +2120,44 @@ do_atrlock(dbref player, const char *arg1, const char *arg2, * \param arg2 the name of the new owner (or "me"). */ void -do_atrchown(dbref player, const char *arg1, const char *arg2) +do_atrchown(dbref player, const char *xarg1, const char *arg2) { dbref thing, new_owner; - char *p; + char *p, *arg1; ATTR *ptr; - if (!arg1 || !*arg1) { + if (!xarg1 || !*xarg1) { notify(player, T("You need to give an object/attribute pair.")); return; } + + arg1 = mush_strdup(xarg1, "atrchown.string"); + if (!(p = strchr(arg1, '/')) || !(*(p + 1))) { notify(player, T("You need to give an object/attribute pair.")); + mush_free(arg1, "atrchown.string"); return; } *p++ = '\0'; if ((thing = noisy_match_result(player, arg1, NOTYPE, MAT_EVERYTHING)) == - NOTHING) + NOTHING) { + mush_free(arg1, "atrchown.string"); return; + } if (ooref != NOTHING && ooref != player && !God(player)) { notify(player, T("Permission denied.")); + mush_free(arg1, "atrchown.string"); return; } else if (!Owns(player, thing) && !God(player)) { notify(player, T("Permission denied.")); + mush_free(arg1, "atrchown.string"); return; } if (!controls(player, thing)) { notify(player, T("Permission denied.")); + mush_free(arg1, "atrchown.string"); return; } @@ -2137,8 +2165,10 @@ do_atrchown(dbref player, const char *arg1, const char *arg2) new_owner = player; else new_owner = lookup_player(arg2); + if (new_owner == NOTHING) { notify(player, T("I can't find that player")); + mush_free(arg1, "atrchown.string"); return; } @@ -2147,40 +2177,36 @@ do_atrchown(dbref player, const char *arg1, const char *arg2) if (Can_Write_Attr(player, thing, ptr)) { if (!controls(player, Owner(thing))) { notify(player, T("You can only chown an attribute to yourself.")); + mush_free(arg1, "atrchown.string"); return; } AL_CREATOR(ptr) = ooref != NOTHING ? Owner(ooref) : Owner(new_owner); notify(player, T("Attribute owner changed.")); + mush_free(arg1, "atrchown.string"); return; } else { notify(player, T("You don't have the permission to chown that.")); + mush_free(arg1, "atrchown.string"); return; } } else notify(player, T("No such attribute.")); + mush_free(arg1, "atrchown.string"); } -/** 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_attr"); - 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; + return slab_malloc(attrib_slab, hint); } /** Traversal routine for Can_Read_Attr. @@ -2367,7 +2393,6 @@ can_write_attr_internal(dbref player, dbref obj, ATTR * atr, int safe) return 1; } - /** Remove all child attributes from root attribute that can be. * \param player object doing a @wipe. * \param thing object being @wiped. @@ -2412,32 +2437,14 @@ atr_clear_children(dbref player, dbref thing, ATTR *root) } -/** 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; -} - /** Push a now-unused attribute onto the free list * \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. @@ -2462,7 +2469,7 @@ atr_free_one(ATTR *a) if (a->data) chunk_delete(a->data); - push_free_list(a); + free_atr(a); } /** Return the compressed data for an attribute. @@ -2474,12 +2481,13 @@ unsigned char const * atr_get_compressed_data(ATTR * atr) { static unsigned char buffer[BUFFER_LEN * 2]; - unsigned int len; + static unsigned char const empty_string[] = { 0 }; + size_t len; if (!atr->data) - return (unsigned char *) ""; + return empty_string; len = chunk_fetch(atr->data, buffer, sizeof(buffer)); if (len > sizeof(buffer)) - return (unsigned char *) ""; + return empty_string; buffer[len] = '\0'; return buffer; } diff --git a/src/boolexp.c b/src/boolexp.c index e4b3864..9e59408 100644 --- a/src/boolexp.c +++ b/src/boolexp.c @@ -21,7 +21,7 @@ * boolexp. Now, it turns the parse tree into bytecode that can be * stored in the chunk manager. It probably also evaluates faster, but * no profiling has been done to support this claim. It certainly - * involves less non-tail recursion. + * involves less non-tail recursion and better cache behavior. * * It's a three-stage process. First, the lock string is turned into a * parse tree. Second, the tree is walked and "assembler" instructions @@ -77,6 +77,10 @@ * the logic when ands, ors and nots are being used together. For * example, !a|!b can become !(a&b). * + * The only optimization done right now is thread jumping: If a jump + * would move the program counter to another jump operation, it instead + * goes to that jump's destination. + * * There's more useful room for improvement in the lock * @warnings. Checking things like flag and power keys for valid flags * comes to mind. @@ -88,8 +92,11 @@ #include #include - +#ifdef HAVE_STDINT_H +#include +#endif #include "conf.h" +#include "dbdefs.h" #include "mushdb.h" #include "match.h" #include "externs.h" @@ -97,10 +104,12 @@ #include "parse.h" #include "attrib.h" #include "flags.h" -#include "dbdefs.h" #include "log.h" +#ifdef CHAT_SYSTEM #include "extchat.h" +#endif #include "strtree.h" +#include "mymalloc.h" #include "confmagic.h" #ifdef WIN32 @@ -218,7 +227,7 @@ struct bvm_asmnode { * the bytecode. The nodes are part of a linked list. */ struct bvm_strnode { char *s; /**< The string */ - int len; /**< Its length */ + size_t len; /**< Its length */ struct bvm_strnode *next; /**< Pointer to the next node */ }; @@ -230,7 +239,7 @@ struct bvm_asm { struct bvm_strnode *shead; /**< The start of the list of strings */ struct bvm_strnode *stail; /**< The end of the list */ int label; /**< The current label id to use */ - int strcount; /**< The number of nodes in the string list */ + size_t strcount; /**< The number of nodes in the string list */ }; /** The flag lock key (A^B) only allows a few values for A. This @@ -258,14 +267,14 @@ static struct flag_lock_types flag_locks[] = { {"SWITCH", OP_TSWITCHES}, {"LEVEL", OP_TLEVEL}, {"POWERGROUP", OP_TPWRGRP}, - {NULL, 0} + {NULL, OP_RET} }; -static unsigned char * +static uint8_t * safe_get_bytecode(boolexp b) __attribute_malloc__; -static unsigned char * -get_bytecode(boolexp b, u_int_16 * storelen); +static uint8_t * +get_bytecode(boolexp b, uint16_t * storelen); static struct boolexp_node * alloc_bool(void) __attribute_malloc__; @@ -311,9 +320,9 @@ generate_bvm_asm(struct boolexp_node *b) static void generate_bvm_asm1(struct bvm_asm *a, struct boolexp_node *b, boolexp_type outer); -static int +static size_t pos_of_label(struct bvm_asm *a, int label); -static int +static size_t offset_to_string(struct bvm_asm *a, int c); static struct bvm_asmnode * insn_after_label(struct bvm_asm *a, int label); @@ -357,11 +366,11 @@ extern SWITCH_VALUE switch_list[]; * \param b the boolexp to retrieve. * \return a malloced copy of the bytecode. */ -static unsigned char * +static uint8_t * safe_get_bytecode(boolexp b) { - unsigned char *bytecode; - u_int_16 len; + uint8_t *bytecode; + uint16_t len; len = chunk_len(b); bytecode = mush_malloc(len, "boolexp.bytecode"); @@ -373,11 +382,11 @@ safe_get_bytecode(boolexp b) * \param b The boolexp to retrieve. * \return a static copy of the bytecode. */ -static unsigned char * -get_bytecode(boolexp b, u_int_16 * storelen) +static uint8_t * +get_bytecode(boolexp b, uint16_t * storelen) { - unsigned static char bytecode[BUFFER_LEN * 2]; - u_int_16 len; + static uint8_t bytecode[BUFFER_LEN * 2]; + uint16_t len; len = chunk_fetch(b, bytecode, sizeof bytecode); if (storelen) @@ -397,8 +406,8 @@ boolexp dup_bool(boolexp b) { boolexp r; - unsigned char *bytecode; - u_int_16 len = 0; + uint8_t *bytecode; + uint16_t len = 0; if (b == TRUE_BOOLEXP) return TRUE_BOOLEXP; @@ -433,7 +442,7 @@ sizeof_boolexp(boolexp b) if (b == TRUE_BOOLEXP) return 0; else - return chunk_len(b); + return (int) chunk_len(b); } /** Evaluate a boolexp. @@ -471,12 +480,12 @@ eval_boolexp(dbref player /* The player trying to pass */ , int div, div2; int r = 0; char *s = NULL; - unsigned char *bytecode, *pc; + uint8_t *bytecode, *pc; bytecode = pc = safe_get_bytecode(b); while (1) { - op = (bvm_opcode) * pc; + op = (bvm_opcode) *pc; memcpy(&arg, pc + 1, sizeof arg); pc += INSN_LEN; switch (op) { @@ -808,11 +817,11 @@ unparse_boolexp(dbref player, boolexp b, enum u_b_f flag) bytecode = pc = get_bytecode(b, NULL); while (1) { - op = (bvm_opcode) * pc; + op = (bvm_opcode) *pc; memcpy(&arg, pc + 1, sizeof arg); pc += INSN_LEN; /* Handle most negation cases */ - if (op != OP_RET && (bvm_opcode) * pc == OP_NEGR && op != OP_PAREN) + if (op != OP_RET && (bvm_opcode) *pc == OP_NEGR && op != OP_PAREN) safe_chr('!', boolexp_buf, &buftop); switch (op) { case OP_JMPT: @@ -840,7 +849,7 @@ unparse_boolexp(dbref player, boolexp b, enum u_b_f flag) int pstack = 1, parg; unsigned char *tpc = pc; while (1) { - if ((bvm_opcode) * tpc == OP_PAREN) { + if ((bvm_opcode) *tpc == OP_PAREN) { memcpy(&parg, tpc + 1, sizeof parg); if (parg) pstack--; @@ -853,7 +862,7 @@ unparse_boolexp(dbref player, boolexp b, enum u_b_f flag) } tpc += INSN_LEN; } - if ((bvm_opcode) * tpc == OP_NEGR) + if ((bvm_opcode) *tpc == OP_NEGR) safe_strl("!(", 2, boolexp_buf, &buftop); else safe_chr('(', boolexp_buf, &buftop); @@ -982,7 +991,7 @@ alloc_bool(void) { struct boolexp_node *b; - b = mush_malloc(sizeof *b, "boolexp_node"); + b = mush_malloc(sizeof *b, "boolexp.node"); b->data.sub.a = NULL; b->data.sub.b = NULL; @@ -997,7 +1006,7 @@ alloc_bool(void) static void free_bool(struct boolexp_node *b) { - mush_free(b, "boolexp_node"); + mush_free(b, "boolexp.node"); } /** Free a boolexp ast node. @@ -1409,6 +1418,8 @@ gen_label_id(struct bvm_asm *a) return l; } +slab *bvm_asmnode_slab = NULL; + /** Add an instruction to the assembler list. * \param a the assembler list. * \param op the opcode of the instruction. @@ -1422,7 +1433,8 @@ append_insn(struct bvm_asm *a, bvm_opcode op, int arg, const char *s) if (s) { struct bvm_strnode *newstr; - int count = 0, found = 0; + uint32_t count = 0; + bool found = 0; /* Look for an existing string */ for (newstr = a->shead; newstr; newstr = newstr->next, count++) { @@ -1454,7 +1466,9 @@ append_insn(struct bvm_asm *a, bvm_opcode op, int arg, const char *s) } } - newop = mush_malloc(sizeof *newop, "bvm.asmnode"); + if (bvm_asmnode_slab == NULL) + bvm_asmnode_slab = slab_create("bvm.asmnode", sizeof *newop); + newop = slab_malloc(bvm_asmnode_slab, NULL); if (!newop) mush_panic(T("Unable to allocate memory for boolexp asm node!")); newop->op = op; @@ -1582,16 +1596,13 @@ generate_bvm_asm(struct boolexp_node *b) static void free_bvm_asm(struct bvm_asm *a) { - struct bvm_asmnode *i, *tmp1; struct bvm_strnode *s, *tmp2; if (!a) return; - for (i = a->head; i; i = tmp1) { - tmp1 = i->next; - mush_free(i, "bvm.asmnode"); - } + slab_destroy(bvm_asmnode_slab); + bvm_asmnode_slab = NULL; for (s = a->shead; s; s = tmp2) { tmp2 = s->next; @@ -1606,10 +1617,10 @@ free_bvm_asm(struct bvm_asm *a) * \param the id of the label to find. * \return the number of instructions before the label. */ -static int +static size_t pos_of_label(struct bvm_asm *as, int label) { - int offset = 0; + size_t offset = 0; struct bvm_asmnode *a; for (a = as->head; a; a = a->next) { if (a->op == OP_LABEL && a->arg == label) @@ -1625,10 +1636,10 @@ pos_of_label(struct bvm_asm *as, int label) * \param c The c-th string is the one that's wanted. * \return the distance from the start of the string section to the start of the c-th string. */ -static int +static size_t offset_to_string(struct bvm_asm *a, int c) { - int offset = 0; + size_t offset = 0; int n = 0; struct bvm_strnode *s; @@ -1686,7 +1697,7 @@ opt_thread_jumps(struct bvm_asm *a) /* Avoid useless conditional jumps on different conditions by jumping to the next instruction after. Ex: a&b|c */ struct bvm_asmnode *newlbl; - newlbl = mush_malloc(sizeof *newlbl, "bvm.asmnode"); + newlbl = slab_malloc(bvm_asmnode_slab, NULL); if (!newlbl) mush_panic(T ("Unable to allocate memory for boolexp asm node!")); @@ -1729,7 +1740,7 @@ emit_bytecode(struct bvm_asm *a, int derefs) struct bvm_asmnode *i; struct bvm_strnode *s; unsigned char *pc, *bytecode; - u_int_16 len, blen; + uint16_t len, blen; if (!a) return TRUE_BOOLEXP; @@ -1953,7 +1964,7 @@ print_bytecode(boolexp b) printf("Total length of bytecode+strings: %d bytes\n", len); while (1) { - op = (bvm_opcode) * pc; + op = (bvm_opcode) *pc; memcpy(&arg, pc + 1, sizeof arg); pc += INSN_LEN; printf("%-5d ", pos); @@ -2092,7 +2103,7 @@ check_lock(dbref player, dbref i, const char *name, boolexp be) bytecode = pc = get_bytecode(be, NULL); while (1) { - op = (bvm_opcode) * pc; + op = (bvm_opcode) *pc; memcpy(&arg, pc + 1, sizeof arg); pc += INSN_LEN; switch (op) { diff --git a/src/bsd.c b/src/bsd.c index 5f732ad..b1f3dc9 100644 --- a/src/bsd.c +++ b/src/bsd.c @@ -24,6 +24,7 @@ #include #include #include +#include #define EINTR WSAEINTR #define EWOULDBLOCK WSAEWOULDBLOCK #define MAXHOSTNAMELEN 32 @@ -34,6 +35,11 @@ #endif #ifdef I_SYS_TIME #include +#ifdef TIME_WITH_SYS_TIME +#include +#endif +#else +#include #endif #include #include @@ -53,10 +59,6 @@ #include #endif #endif /* !WIN32 */ -#include -#ifdef I_SYS_WAIT -#include -#endif #include #include #include @@ -65,9 +67,12 @@ #ifdef I_SYS_SELECT #include #endif -#ifdef I_UNISTD +#ifdef HAVE_UNISTD_H #include #endif +#ifdef HAVE_SYS_UIO_H +#include +#endif #ifdef HAS_GETRLIMIT #include #endif @@ -75,21 +80,22 @@ #ifdef I_FLOATINGPOINT #include #endif +#ifdef HAVE_IEEEFP_H +#include +#endif #include #include #include -#include "conf.h" - -#if defined(WIN32) && defined(INFO_SLAVE) -#undef INFO_SLAVE -#endif +#ifdef HAVE_SYS_INOTIFY_H +#include +#endif -#ifndef COMPILE_CONSOLE -#ifdef INFO_SLAVE -#include -#endif +#ifdef HAVE_FAM_H +#include #endif + +#include "conf.h" #include "externs.h" #include "chunk.h" @@ -107,9 +113,23 @@ #include "version.h" #include "mysocket.h" #include "ident.h" +#include "htab.h" +#include "help.h" + +#ifdef COMPILE_CONSOLE +#undef INFO_SLAVE +#endif + +#ifndef WIN32 +#include "wait.h" +#ifdef INFO_SLAVE +#include "lookup.h" +#endif +#endif + #include "strtree.h" #include "log.h" -#include "pcre.h" +#include "mypcre.h" #ifndef COMPILE_CONSOLE #ifdef HAS_OPENSSL #include "myssl.h" @@ -120,22 +140,12 @@ #include "attrib.h" #include "game.h" #include "dbio.h" +#include "intmap.h" #include "confmagic.h" #include "modules.h" #include "lua.h" #include "mushlua.h" #include "modules.h" -#ifdef HAS_WAITPID -/** What does wait*() return? */ -#define WAIT_TYPE int -#else -#ifdef UNION_WAIT -#define WAIT_TYPE union wait -#else -#define WAIT_TYPE int -#endif -#endif - /* BSD 4.2 and maybe some others need these defined */ #ifndef FD_ZERO @@ -170,12 +180,12 @@ void chat_player_announce(dbref player, char *msg, int ungag); static int login_number = 0; static int under_limit = 1; -char cf_motd_msg[BUFFER_LEN]; /**< The message of the day */ -char cf_downmotd_msg[BUFFER_LEN]; /**< The down message */ -char cf_fullmotd_msg[BUFFER_LEN]; /**< The 'mush full' message */ -static char poll_msg[DOING_LEN]; -char confname[BUFFER_LEN]; /**< Name of the config file */ -char errlog[BUFFER_LEN]; /**< Name of the error log file */ +char cf_motd_msg[BUFFER_LEN] = { '\0' }; /**< The message of the day */ +char cf_downmotd_msg[BUFFER_LEN] = { '\0' }; /**< The down message */ +char cf_fullmotd_msg[BUFFER_LEN] = { '\0' }; /**< The 'mush full' message */ +static char poll_msg[DOING_LEN] = { '\0' }; +char confname[BUFFER_LEN] = { '\0' }; /**< Name of the config file */ +char errlog[BUFFER_LEN] = { '\0' }; /**< Name of the error log file */ /* Default Connection flags for certain clients */ @@ -272,6 +282,7 @@ dummy_msgs() #endif DESC *descriptor_list = NULL; /**< The linked list of descriptors */ +intmap *descs_by_fd = NULL; /**< Map of ports to DESC* objects */ #ifndef COMPILE_CONSOLE static int sock; @@ -282,24 +293,13 @@ SSL *ssl_master_socket = NULL; /**< Master SSL socket for ssl port */ #ifdef WIN32 static WSADATA wsadata; #endif -static int maxd = 0; +int maxd = 0; #endif /* COMPILE_CONSOLE */ int restarting = 0; /**< Are we restarting the server after a reboot? */ static int ndescriptors = 0; extern const unsigned char *tables; -#ifndef COMPILE_CONSOLE -#ifdef INFO_SLAVE -static fd_set info_pending; -static int info_slave; -Pid_t info_slave_pid = -1; /**< Process id of the info_slave process */ -int info_slave_state = 0; /**< State of the info_slave process */ -static int info_query_spill, info_reap_spill; -static time_t info_queue_time = 0; -#endif -#endif - sig_atomic_t signal_shutdown_flag = 0; /**< Have we caught a shutdown signal? */ sig_atomic_t signal_dump_flag = 0; /**< Have we caught a dump signal? */ @@ -309,7 +309,7 @@ static void init_rlimit(void); #ifndef BOOLEXP_DEBUGGING #ifdef WIN32SERVICES void shutdown_checkpoint(void); -void mainthread(int argc, char **argv); +int mainthread(int argc, char **argv); #else int main(int argc, char **argv); #endif @@ -334,9 +334,7 @@ static void shovechars(void); static int how_many_fds(void); static void shovechars(Port_t port, Port_t sslport); static int test_connection(int newsock); -#ifndef INFO_SLAVE -static DESC *new_connection(int oldsock, int *result, int use_ssl); -#endif +static DESC *new_connection(int oldsock, int *result, bool use_ssl); #endif /* COMPILE_CONSOLE */ static void clearstrings(DESC *d); @@ -372,7 +370,7 @@ static void fcache_dump(DESC *d, FBLOCK fp[2], const unsigned char *prefix); static int fcache_read(FBLOCK *cp, const char *filename); static void logout_sock(DESC *d); static void shutdownsock(DESC *d); -static DESC *initializesock(int s, char *addr, char *ip, int use_ssl); +DESC *initializesock(int s, char *addr, char *ip, int use_ssl); int process_output(DESC *d); /* Notify.c */ extern void free_text_block(struct text_block *t); @@ -405,26 +403,25 @@ void reaper(int sig); #ifndef WIN32 sig_atomic_t dump_error = 0; WAIT_TYPE dump_status = 0; +#ifdef INFO_SLAVE +sig_atomic_t slave_error = 0; +#endif #endif -extern Pid_t forked_dump_pid; /**< Process id of forking dump process */ +extern pid_t forked_dump_pid; /**< Process id of forking dump process */ static void dump_users(DESC *call_by, char *match, int doing); static const char *time_format_1(long int dt); static const char *time_format_2(long int dt); void inactivity_check(void); -#ifndef COMPILE_CONSOLE -#ifdef INFO_SLAVE -static void make_info_slave(void); -static void promote_info_slave(void); -static void query_info_slave(int fd); -static void reap_info_slave(void); -void kill_info_slave(void); -sig_atomic_t slave_error = 0; -#endif -#endif -#endif void reopen_logs(void); void load_reboot_db(void); +static bool in_suid_root_mode = 0; +static char *pidfile = NULL; +static char **saved_argv = NULL; + +int file_watch_init(void); +void file_watch_event(int); + #ifdef HAS_GETRLIMIT static void init_rlimit(void) @@ -461,7 +458,10 @@ init_rlimit(void) /* Under WIN32, MUSH is a "service", so we just start a thread here. * The real "main" is in win32/services.c */ -void + +/* TODO: Re-implement's Ari's COMPILE_CONSOLE defines.. */ + +int mainthread(int argc, char **argv) #else /** The main function. @@ -477,16 +477,104 @@ main(int argc, char **argv) FILE *id; #endif FILE *newerr; + bool detach_session = 1; struct module_entry_t *m; void (*handle)(); +/* disallow running as root on unix. + * This is done as early as possible, before translation is initialized. + * Hence, no T()s around messages. + */ +#ifndef WIN32 +#ifdef HAVE_GETUID + if (getuid() == 0) { + fputs("Please run the server as another user.\n", stderr); + fputs("PennMUSH will not run as root as a security measure.\n", stderr); + return EXIT_FAILURE; + } + /* Add suid-root checks here. */ +#endif +#ifdef HAVE_GETEUID + if (geteuid() == 0) { + fprintf(stderr, "The %s binary is set suid and owned by root.\n", argv[0]); +#ifdef HAVE_SETEUID + fprintf(stderr, "Changing effective user to %d.\n", getuid()); + seteuid(getuid()); + in_suid_root_mode = 1; +#endif + } +#endif /* HAVE_GETEUID */ +#endif /* !WIN32 */ + /* read the configuration file */ - if (argc < 2) { - fprintf(stderr, "ERROR: Usage: %s /path/to/config_file\n", argv[0]); - exit(2); + if (argc < 2) { + fprintf(stderr, + "WARNING: Called without a config file argument. Assuming mush.cnf\n"); + strcpy(confname, "mush.cnf"); + } else { + int n; + for (n = 1; n < argc; n++) { + if (argv[n][0] == '-') { + if (strcmp(argv[n], "--no-session") == 0) + detach_session = 0; + else if (strncmp(argv[n], "--pid-file", 10) == 0) { + char *eq; + if ((eq = strchr(argv[n], '='))) + pidfile = eq + 1; + else { + if (n + 1 >= argc) { + fprintf(stderr, "%s: --pid-file needs a filename.\n", argv[0]); + return EXIT_FAILURE; + } + pidfile = argv[n + 1]; + n++; + } + } else + fprintf(stderr, "%s: unknown option \"%s\"\n", argv[0], argv[n]); + } else { + mush_strncpy(confname, argv[n], BUFFER_LEN); + break; + } + } + } + +#ifdef HAVE_FORK + /* Fork off and detach from controlling terminal. */ + if (detach_session) { + pid_t child; + + child = fork(); + if (child < 0) { + /* Print a warning and continue */ + penn_perror("fork"); + } else if (child > 0) { + /* Parent process of a successful fork() */ + return EXIT_SUCCESS; + } else { + /* Child process */ + if (new_process_session() < 0) + penn_perror("Couldn't create a new process session"); + } + } +#endif + +#ifdef HAVE_GETPID + if (pidfile) { + FILE *f; + if (!(f = fopen(pidfile, "w"))) { + fprintf(stderr, "%s: Unable to write to pidfile '%s'\n", argv[0], + pidfile); + return EXIT_FAILURE; + } + fprintf(f, "%d\n", getpid()); + fclose(f); } +#endif + + saved_argv = argv; + #ifdef WIN32 { @@ -506,17 +594,18 @@ main(int argc, char **argv) init_rlimit(); /* unlimit file descriptors */ #endif - /* These are FreeBSDisms to fix floating point exceptions */ -#ifdef HAS_FPSETROUND + /* These are BSDisms to fix floating point exceptions */ +#ifdef HAVE_FPSETROUND fpsetround(FP_RN); #endif -#ifdef HAS_FPSETMASK +#ifdef HAVE_FPSETMASK fpsetmask(0L); #endif + time(&mudtime); + options.mem_check = 1; - time(&mudtime); /* Initialize Module interface */ modules_init(); @@ -558,19 +647,10 @@ main(int argc, char **argv) /* Build the locale-dependant tables used by PCRE */ tables = pcre_maketables(); -/* this writes a file used by the restart script to check for active mush */ -#ifdef AUTORESTART - id = fopen("runid", "w"); - fprintf(id, "%d", getpid()); - fclose(id); -#endif - /* Start lua enivonrment * Eventually we'll conver the config file to a big lua script, so we'll start the lua envionrment before it */ mush_lua_start(); - strncpy(confname, argv[1], BUFFER_LEN - 1); - confname[BUFFER_LEN - 1] = '\0'; init_game_config(confname); /* save a file descriptor */ @@ -587,8 +667,6 @@ main(int argc, char **argv) fclose(newerr); } - init_qids(); - /* load databases */ if (init_game_dbs() < 0) { do_rawlog(LT_ERR, T("ERROR: Couldn't load databases! Exiting.")); @@ -601,12 +679,12 @@ main(int argc, char **argv) set_signals(); -#ifndef COMPILE_CONSOLE #ifdef INFO_SLAVE - make_info_slave(); -#endif + init_info_slave(); #endif + descs_by_fd = im_new(); + /* go do it */ #ifdef CSRI #ifdef CSRI_DEBUG @@ -623,10 +701,8 @@ main(int argc, char **argv) #else shovechars((Port_t) TINYPORT, (Port_t) SSLPORT); #endif -#ifdef CSRI -#ifdef CSRI_DEBUG +#if defined(CSRI_DEBUG) && defined(CSRI) mal_verify(1); -#endif #endif /* someone has told us to shut down */ @@ -646,11 +722,9 @@ main(int argc, char **argv) sql_shutdown(); mush_lua_stop(); /* shutdown the lua environment */ -#ifndef COMPILE_CONSOLE #ifdef INFO_SLAVE kill_info_slave(); #endif -#endif #ifdef WIN32SERVICES /* Keep service manager happy */ @@ -669,6 +743,9 @@ main(int argc, char **argv) end_all_logs(); + if (pidfile) + remove(pidfile); + #ifdef CSRI #ifdef CSRI_PROFILESIZES mal_statsdump(stderr); @@ -739,6 +816,7 @@ set_signals(void) install_sig_handler(SIGQUIT, signal_shutdown); install_sig_handler(SIGINT, signal_shutdown); install_sig_handler(SIGTERM, bailout); + install_sig_handler(SIGCHLD, reaper); #else /* Win32 stuff: * No support for SIGUSR2 or SIGINT. @@ -751,10 +829,6 @@ set_signals(void) #endif #endif -#ifndef WIN32 - install_sig_handler(SIGCHLD, reaper); -#endif - } #ifdef WIN32 @@ -910,12 +984,26 @@ bad_empabb_value: } +extern slab *text_block_slab; + +static void +setup_desc(int sock, bool use_ssl) +{ + DESC *newd; + int result; + + if (!(newd = new_connection(sock, &result, use_ssl))) { + if (test_connection(result) < 0) + return; + } else { + ndescriptors++; + if (newd->descriptor >= maxd) + maxd = newd->descriptor + 1; + } +} + static void -#ifdef COMPILE_CONSOLE -shovechars() -#else shovechars(Port_t port, Port_t sslport __attribute__ ((__unused__))) -#endif { /* this is the main game loop */ @@ -927,51 +1015,41 @@ shovechars(Port_t port, Port_t sslport __attribute__ ((__unused__))) int found; int queue_timeout; DESC *d, *dnext; -#ifndef COMPILE_CONSOLE -#ifndef INFO_SLAVE - DESC *newd; - int result; -#endif int avail_descriptors; #ifdef INFO_SLAVE union sockaddr_u addr; socklen_t addr_len; int newsock; #endif -#endif /* COMPILE_CONSOLE */ unsigned long input_ready, output_ready; + int notify_fd = -1; -#ifdef COMPILE_CONSOLE - d = initializesock(0, "localhost", "127.0.0.1", 0); -#else if (!restarting) { - sock = make_socket(port, NULL, NULL, MUSH_IP_ADDR); + sock = make_socket(port, SOCK_STREAM, NULL, NULL, MUSH_IP_ADDR); if (sock >= maxd) maxd = sock + 1; #ifdef HAS_OPENSSL if (sslport) { - sslsock = make_socket(sslport, NULL, NULL, SSL_IP_ADDR); + sslsock = make_socket(sslport, SOCK_STREAM, NULL, NULL, SSL_IP_ADDR); ssl_master_socket = ssl_setup_socket(sslsock); if (sslsock >= maxd) maxd = sslsock + 1; } #endif } -#endif /* COMPILE_CONSOLE */ our_gettimeofday(&last_slice); -#ifndef COMPILE_CONSOLE avail_descriptors = how_many_fds() - 4; #ifdef INFO_SLAVE avail_descriptors -= 2; /* reserve some more for setting up the slave */ - FD_ZERO(&info_pending); #endif /* done. print message to the log */ do_rawlog(LT_ERR, "%d file descriptors available.", avail_descriptors); -#endif /* COMPILE_CONSOLE */ do_rawlog(LT_ERR, "RESTART FINISHED."); + notify_fd = file_watch_init(); + our_gettimeofday(&then); while (shutdown_flag == 0) { @@ -992,6 +1070,7 @@ shovechars(Port_t port, Port_t sslport __attribute__ ((__unused__))) /* Check signal handler flags */ #ifndef WIN32 + if (dump_error) { if (WIFSIGNALED(dump_status)) { do_rawlog(LT_ERR, T("ERROR! forking dump exited with signal %d"), @@ -1006,7 +1085,7 @@ shovechars(Port_t port, Port_t sslport __attribute__ ((__unused__))) dump_error = 0; dump_status = 0; } -#if defined(INFO_SLAVE) && !defined(COMPILE_CONSOLE) +#ifdef INFO_SLAVE if (slave_error) { do_rawlog(LT_ERR, T("info_slave on pid %d exited unexpectedly!"), slave_error); @@ -1015,12 +1094,10 @@ shovechars(Port_t port, Port_t sslport __attribute__ ((__unused__))) #endif #endif /* !WIN32 */ + if (signal_shutdown_flag) { flag_broadcast(0, 0, T("GAME: Shutdown by external signal")); do_rawlog(LT_ERR, T("SHUTDOWN by external signal")); -#ifdef AUTORESTART - system("touch NORESTART"); -#endif shutdown_flag = 1; } @@ -1063,7 +1140,6 @@ shovechars(Port_t port, Port_t sslport __attribute__ ((__unused__))) FD_ZERO(&input_set); FD_ZERO(&output_set); -#ifndef COMPILE_CONSOLE if (ndescriptors < avail_descriptors) FD_SET(sock, &input_set); #ifdef HAS_OPENSSL @@ -1071,40 +1147,23 @@ shovechars(Port_t port, Port_t sslport __attribute__ ((__unused__))) FD_SET(sslsock, &input_set); #endif #ifdef INFO_SLAVE - if (info_slave_state > 0) + if (info_slave_state == INFO_SLAVE_PENDING) FD_SET(info_slave, &input_set); #endif -#endif /* COMPILE_CONSOLE */ for (d = descriptor_list; d; d = d->next) { if (d->input.head) { timeout.tv_sec = slice_timeout.tv_sec; timeout.tv_usec = slice_timeout.tv_usec; -#ifdef COMPILE_CONSOLE - } else { - if(d->descriptor == 0) - FD_SET(STDIN_FILENO, &input_set); - else - FD_SET(d->descriptor, &input_set); - } - if (d->output.head) { - if(d->descriptor == 0) - FD_SET(STDOUT_FILENO, &output_set); - else - FD_SET(d->descriptor, &output_set); - } -#else /* COMPILE_CONSOLE */ } else FD_SET(d->descriptor, &input_set); if (d->output.head) FD_SET(d->descriptor, &output_set); -#endif /* COMPILE_CONSOLE */ } -#ifdef COMPILE_CONSOLE - found = select(2, &input_set, &output_set, (fd_set *) 0, &timeout); -#else + if (notify_fd >= 0) + FD_SET(notify_fd, &input_set); + found = select(maxd, &input_set, &output_set, (fd_set *) 0, &timeout); -#endif if (found < 0) { #ifdef WIN32 if (found == SOCKET_ERROR && WSAGetLastError() != WSAEINTR) @@ -1112,21 +1171,13 @@ shovechars(Port_t port, Port_t sslport __attribute__ ((__unused__))) if (errno != EINTR) #endif { - perror("select"); + penn_perror("select"); return; } -#ifndef COMPILE_CONSOLE #ifdef INFO_SLAVE - now = mudtime; - if (info_slave_state == 2 && now > info_queue_time + 30) { - /* rerun any pending queries that got lost */ - info_queue_time = now; - for (newsock = 0; newsock < maxd; newsock++) - if (FD_ISSET(newsock, &info_pending)) - query_info_slave(newsock); - } + if (info_slave_state == INFO_SLAVE_PENDING) + update_pending_info_slaves(); #endif -#endif /* COMPILE_CONSOLE */ } else { /* if !found then time for robot commands */ @@ -1137,99 +1188,62 @@ shovechars(Port_t port, Port_t sslport __attribute__ ((__unused__))) do_top(options.active_q_chunk); } now = mudtime; -#ifndef COMPILE_CONSOLE #ifdef INFO_SLAVE - if (info_slave_state > 0 && FD_ISSET(info_slave, &input_set)) { - if (info_slave_state == 1) - promote_info_slave(); - else { - reap_info_slave(); - } - } else if (info_slave_state == 2 && now > info_queue_time + 30) { + if (info_slave_state == INFO_SLAVE_PENDING + && FD_ISSET(info_slave, &input_set)) { + reap_info_slave(); + } else if (info_slave_state == INFO_SLAVE_PENDING + && now > info_queue_time + 30) { /* rerun any pending queries that got lost */ - info_queue_time = now; - for (newsock = 0; newsock < maxd; newsock++) - if (FD_ISSET(newsock, &info_pending)) - query_info_slave(newsock); + update_pending_info_slaves(); } if (FD_ISSET(sock, &input_set)) { - addr_len = sizeof(addr); - newsock = accept(sock, (struct sockaddr *) &addr, &addr_len); - if (newsock < 0) { - if (test_connection(newsock) < 0) - continue; /* this should _not_ be return. */ - } - ndescriptors++; - query_info_slave(newsock); - if (newsock >= maxd) - maxd = newsock + 1; + if (!info_slave_halted) { + addr_len = sizeof(addr); + newsock = accept(sock, (struct sockaddr *) &addr, &addr_len); + if (newsock < 0) { + if (test_connection(newsock) < 0) + continue; /* this should _not_ be return. */ + } + ndescriptors++; + query_info_slave(newsock); + if (newsock >= maxd) + maxd = newsock + 1; + } else + setup_desc(sock, false); } #ifdef HAS_OPENSSL if (sslsock && FD_ISSET(sslsock, &input_set)) { - addr_len = sizeof(addr); - newsock = accept(sslsock, (struct sockaddr *) &addr, &addr_len); - if (newsock < 0) { - if (test_connection(newsock) < 0) - continue; /* this should _not_ be return. */ - } - ndescriptors++; - query_info_slave(newsock); - if (newsock >= maxd) - maxd = newsock + 1; + if (!info_slave_halted) { + addr_len = sizeof(addr); + newsock = accept(sslsock, (struct sockaddr *) &addr, &addr_len); + if (newsock < 0) { + if (test_connection(newsock) < 0) + continue; /* this should _not_ be return. */ + } + ndescriptors++; + query_info_slave(newsock); + if (newsock >= maxd) + maxd = newsock + 1; + } else + setup_desc(sslsock, true); } #endif #else /* INFO_SLAVE */ - if (FD_ISSET(sock, &input_set)) { - if (!(newd = new_connection(sock, &result, 0))) { - if (test_connection(result) < 0) - continue; /* this should _not_ be return. */ - } else { - ndescriptors++; - if (newd->descriptor >= maxd) - maxd = newd->descriptor + 1; - } - } + if (FD_ISSET(sock, &input_set)) + setup_desc(sock, false); #ifdef HAS_OPENSSL - if (sslsock && FD_ISSET(sslsock, &input_set)) { - if (!(newd = new_connection(sslsock, &result, 1))) { - if (test_connection(result) < 0) - continue; /* this should _not_ be return. */ - } else { - ndescriptors++; - if (newd->descriptor >= maxd) - maxd = newd->descriptor + 1; - } - } + if (sslsock && FD_ISSET(sslsock, &input_set)) + setup_desc(sslsock, true); #endif #endif -#endif /* COMPILE_CONSOLE */ + + if (notify_fd >= 0 && FD_ISSET(notify_fd, &input_set)) + file_watch_event(notify_fd); + for (d = descriptor_list; d; d = dnext) { dnext = d->next; -#ifdef COMPILE_CONSOLE - if (d->descriptor == 0) { - input_ready = FD_ISSET(STDIN_FILENO, &input_set); - output_ready = FD_ISSET(STDOUT_FILENO, &output_set); - } else { - input_ready = FD_ISSET(d->descriptor, &input_set); - output_ready = FD_ISSET(d->descriptor, &output_set); - } - if (input_ready) { - if (!process_input(d, output_ready)) { - shutdownsock(d); - if(d->descriptor == 0) - return; - continue; - } - } - if (output_ready) { - if (!process_output(d)) { - shutdownsock(d); - if (d->descriptor == 0) - return; - } - } -#else /* COMPILE_CONSOLE */ input_ready = FD_ISSET(d->descriptor, &input_set); output_ready = FD_ISSET(d->descriptor, &output_set); if (input_ready) { @@ -1242,29 +1256,12 @@ shovechars(Port_t port, Port_t sslport __attribute__ ((__unused__))) if (!process_output(d)) { shutdownsock(d); } -#else /* COMPILE_CONSOLE */ - input_ready = FD_ISSET(d->descriptor, &input_set); - output_ready = FD_ISSET(d->descriptor, &output_set); - if (input_ready) { - if (!process_input(d, output_ready)) { - shutdownsock(d); - continue; - } - } - if (output_ready) { - if (!process_output(d)) { - shutdownsock(d); - } - } -#endif /* COMPILE_CONSOLE */ } -#endif /* COMPILE_CONSOLE */ } } } } -#ifndef COMPILE_CONSOLE static int test_connection(int newsock) { @@ -1274,15 +1271,16 @@ test_connection(int newsock) if (errno && errno != EINTR) #endif { - perror("test_connection"); + penn_perror("test_connection"); return -1; } return newsock; } -#ifndef INFO_SLAVE + + static DESC * -new_connection(int oldsock, int *result, int use_ssl) +new_connection(int oldsock, int *result, bool use_ssl) { int newsock; union sockaddr_u addr; @@ -1324,9 +1322,9 @@ new_connection(int oldsock, int *result, int use_ssl) if (Forbidden_Site(tbuf1) || Forbidden_Site(tbuf2)) { if (!Deny_Silent_Site(tbuf1, AMBIGUOUS) || !Deny_Silent_Site(tbuf2, AMBIGUOUS)) { - do_log(LT_CONN, 0, 0, "[%d/%s/%s] %s (%s %s)", newsock, tbuf1, tbuf2, - T("Refused connection"), T("remote port"), - hi ? hi->port : T("(unknown)")); + do_rawlog(LT_CONN, "[%d/%s/%s] %s (%s %s)", newsock, tbuf1, tbuf2, + T("Refused connection"), T("remote port"), + hi ? hi->port : T("(unknown)")); } shutdown(newsock, 2); closesocket(newsock); @@ -1335,13 +1333,10 @@ new_connection(int oldsock, int *result, int use_ssl) #endif return 0; } - do_log(LT_CONN, 0, 0, T("[%d/%s/%s] Connection opened."), newsock, tbuf1, - tbuf2); + do_rawlog(LT_CONN, T("[%d/%s/%s] Connection opened."), newsock, tbuf1, tbuf2); set_keepalive(newsock); return initializesock(newsock, tbuf1, tbuf2, use_ssl); } -#endif -#endif /* COMPILE_CONSOLE */ static void clearstrings(DESC *d) @@ -1439,14 +1434,13 @@ fcache_read(FBLOCK *fb, const char *filename) release_fd(); if ((fd = open(filename, O_RDONLY, 0)) < 0) { - do_log(LT_ERR, 0, 0, T("Couldn't open cached text file '%s'"), filename); + do_rawlog(LT_ERR, T("Couldn't open cached text file '%s'"), filename); reserve_fd(); return -1; } if (fstat(fd, &sb) < 0) { - do_log(LT_ERR, 0, 0, T("Couldn't get the size of text file '%s'"), - filename); + do_rawlog(LT_ERR, T("Couldn't get the size of text file '%s'"), filename); close(fd); reserve_fd(); return -1; @@ -1454,15 +1448,15 @@ fcache_read(FBLOCK *fb, const char *filename) if (!(fb->buff = mush_malloc(sb.st_size, "fcache_data"))) { - do_log(LT_ERR, 0, 0, T("Couldn't allocate %d bytes of memory for '%s'!"), - (int) sb.st_size, filename); + do_rawlog(LT_ERR, T("Couldn't allocate %d bytes of memory for '%s'!"), + (int) sb.st_size, filename); close(fd); reserve_fd(); return -1; } if ((n = read(fd, fb->buff, sb.st_size)) != sb.st_size) { - do_log(LT_ERR, 0, 0, T("Couldn't read all of '%s'"), filename); + do_rawlog(LT_ERR, T("Couldn't read all of '%s'"), filename); close(fd); mush_free(fb->buff, "fcache_data"); fb->buff = NULL; @@ -1528,8 +1522,7 @@ logout_sock(DESC *d) if (d->connected) { fcache_dump(d, fcache.quit_fcache, NULL); - do_log(LT_CONN, 0, 0, - T("[%d/%s/%s] Logout by %s(#%d) "), + do_rawlog(LT_CONN, T("[%d/%s/%s] Logout by %s(#%d) "), d->descriptor, d->addr, d->ip, Name(d->player), d->player); if(d->last_time > 0) { d->idle_total += difftime(mudtime, d->last_time); @@ -1547,14 +1540,12 @@ logout_sock(DESC *d) login_number--; if (!under_limit && (login_number < MAX_LOGINS)) { under_limit = 1; - do_log(LT_CONN, 0, 0, - T("Below maximum player limit of %d. Logins enabled."), + do_rawlog(LT_CONN, T("Below maximum player limit of %d. Logins enabled."), MAX_LOGINS); } } } else { - do_log(LT_CONN, 0, 0, - T("[%d/%s/%s] Logout, never connected. "), + do_rawlog(LT_CONN, T("[%d/%s/%s] Logout, never connected. "), d->descriptor, d->addr, d->ip); } process_output(d); /* flush our old output */ @@ -1578,9 +1569,6 @@ logout_sock(DESC *d) d->cmds = 0; d->hide = 0; d->doing[0] = '\0'; -#ifdef USE_MAILER - d->mailp = NULL; -#endif d->pinfo.object = NOTHING; d->pinfo.atr = NULL; d->pinfo.lock = 0; @@ -1610,8 +1598,8 @@ shutdownsock(DESC *d) #endif if (d->connected) { - do_log(LT_CONN, 0, 0, T("[%d/%s/%s] Logout by %s(#%d)"), - d->descriptor, d->addr, d->ip, Name(d->player), d->player); + do_rawlog(LT_CONN, T("[%d/%s/%s] Logout by %s(#%d)"), + d->descriptor, d->addr, d->ip, Name(d->player), d->player); if (d->connected != 2) { fcache_dump(d, fcache.quit_fcache, NULL); /* Player was not allowed to log in from the connect screen */ @@ -1632,14 +1620,14 @@ shutdownsock(DESC *d) login_number--; if (!under_limit && (login_number < MAX_LOGINS)) { under_limit = 1; - do_log(LT_CONN, 0, 0, - T("Below maximum player limit of %d. Logins enabled."), - MAX_LOGINS); + do_rawlog(LT_CONN, + T("Below maximum player limit of %d. Logins enabled."), + MAX_LOGINS); } } } else { - do_log(LT_CONN, 0, 0, T("[%d/%s/%s] Connection closed, never connected."), - d->descriptor, d->addr, d->ip); + do_rawlog(LT_CONN, T("[%d/%s/%s] Connection closed, never connected."), + d->descriptor, d->addr, d->ip); } process_output(d); clearstrings(d); @@ -1669,9 +1657,6 @@ shutdownsock(DESC *d) d->cmds = 0; d->hide = 0; d->doing[0] = '\0'; -#ifdef USE_MAILER - d->mailp = NULL; -#endif strncpy(d->addr, "localhost", 100); d->addr[99] = '\0'; strncpy(d->ip, "127.0.0.1", 100); @@ -1716,6 +1701,8 @@ shutdownsock(DESC *d) if (d->next) d->next->prev = d->prev; + im_delete(descs_by_fd, d->descriptor); + #ifdef HAS_OPENSSL if (sslsock && d->ssl) { ssl_close_connection(d->ssl); @@ -1734,7 +1721,7 @@ shutdownsock(DESC *d) } /* ARGSUSED */ -static DESC * +DESC * initializesock(int s, char *addr, char *ip, int use_ssl __attribute__ ((__unused__))) { @@ -1766,12 +1753,9 @@ initializesock(int s, char *addr, char *ip, int use_ssl d->cmds = 0; d->hide = 0; d->doing[0] = '\0'; -#ifdef USE_MAILER - d->mailp = NULL; -#endif - strncpy(d->addr, addr, 100); + mush_strncpy(d->addr, addr, 100); d->addr[99] = '\0'; - strncpy(d->ip, ip, 100); + mush_strncpy(d->ip, ip, 100); d->ip[99] = '\0'; d->conn_flags = CONN_DEFAULT; d->input_chars = 0; @@ -1785,423 +1769,40 @@ initializesock(int s, char *addr, char *ip, int use_ssl d->pinfo.function = NULL; #ifndef COMPILE_CONSOLE #ifdef HAS_OPENSSL - d->ssl = NULL; - d->ssl_state = 0; -#endif -#endif - if (descriptor_list) - descriptor_list->prev = d; - d->next = descriptor_list; - d->prev = NULL; - descriptor_list = d; - d->width = 78; - d->height = 24; -#ifndef COMPILE_CONSOLE -#ifdef HAS_OPENSSL - if (use_ssl && sslsock) { - d->ssl = ssl_listen(d->descriptor, &d->ssl_state); - if (d->ssl_state < 0) { - /* Error we can't handle */ - ssl_close_connection(d->ssl); - d->ssl = NULL; - d->ssl_state = 0; - } - } -#endif - test_telnet(d); -#endif /* COMPILE_CONSOLE */ - welcome_user(d); - for(n = 0; n < MAX_SNOOPS; n++) - d->snooper[n] = -1; - return d; -} - -#ifndef COMPILE_CONSOLE -#ifdef INFO_SLAVE -static void -make_info_slave(void) -{ -#ifdef HAS_SOCKETPAIR - int socks[2]; -#else - union sockaddr_u addr; - socklen_t opt; -#endif - char num[NI_MAXSERV]; - Pid_t child; - int n; - - if (info_slave_state != 0) { - if (info_slave_pid > 0) { - closesocket(info_slave); - kill(info_slave_pid, 15); - info_slave_pid = -1; - } - info_slave_state = 0; - } -#ifdef HAS_SOCKETPAIR - /* Use Posix.1g names... */ -#ifndef AF_LOCAL -#define AF_LOCAL AF_UNIX -#endif - if (socketpair(AF_LOCAL, SOCK_STREAM, 0, socks) < 0) { - perror("creating slave stream socketpair"); - return; - } - if (socks[0] >= maxd) - maxd = socks[0] + 1; - if (socks[1] >= maxd) - maxd = socks[1] + 1; -#else - info_slave = make_socket(0, &addr, &opt, MUSH_IP_ADDR); - if (getsockname(info_slave, (struct sockaddr *) &addr.data, &opt) < 0) { - perror("getsockname"); - fflush(stderr); - closesocket(info_slave); - return; - } - if (getnameinfo(&addr.addr, opt, NULL, 0, num, sizeof num, - NI_NUMERICHOST | NI_NUMERICSERV) != 0) { - perror("getting address of slave stream socket"); - fflush(stderr); - closesocket(info_slave); - return; - } - listen(info_slave, 1); -#endif - child = fork(); - if (child < 0) { - perror("forking info slave"); -#ifdef HAS_SOCKETPAIR - closesocket(socks[0]); - closesocket(socks[1]); -#else - closesocket(info_slave); -#endif - return; - } - if (child) { - info_slave_state = 1; - info_slave_pid = child; -#ifdef HAS_SOCKETPAIR - info_slave = socks[0]; - closesocket(socks[1]); - do_rawlog(LT_ERR, - "Spawning info slave using socketpair, pid %d, ident %d", - child, USE_IDENT); -#else - do_rawlog(LT_ERR, "Spawning info slave on port %s, pid %d, ident %d", - num, child, USE_IDENT); -#endif - } else { - /* Close unneeded fds and sockets */ - for (n = 3; n < maxd; n++) { - if (n == fileno(stderr)) - continue; -#ifdef HAS_SOCKETPAIR - if (n == socks[1]) - continue; -#endif - close(n); - } -#ifdef HAS_SOCKETPAIR - sprintf(num, "%d", socks[1]); -#endif - if (!USE_IDENT) - execl("./info_slave", "./info_slave", num, "-1", USE_DNS ? "1" : "0", - (char *) NULL); - else - execl("./info_slave", "./info_slave", num, tprintf("%d", IDENT_TIMEOUT), - USE_DNS ? "1" : "0", (char *) NULL); - perror("execing info slave"); - exit(1); - } - info_query_spill = 0; - info_reap_spill = 0; - if (info_slave >= maxd) - maxd = info_slave + 1; -#ifdef HAS_SOCKETPAIR - promote_info_slave(); -#endif -} - -static void -promote_info_slave(void) -{ - int j; -#ifndef HAS_SOCKETPAIR - int newsock; - union sockaddr_u addr; - socklen_t addr_len; - char port[NI_MAXSERV]; -#endif - - if (info_slave_state != 1) { - make_info_slave(); - return; - } -#ifndef HAS_SOCKETPAIR - addr_len = MAXSOCKADDR; - newsock = accept(info_slave, (struct sockaddr *) addr.data, &addr_len); - if (newsock < 0) { - perror("accepting info slave connection"); - make_info_slave(); - return; - } - closesocket(info_slave); - info_slave = newsock; -#endif - make_nonblocking(info_slave); - /* Do authentication here, if we care */ - info_slave_state = 2; -#ifdef HAS_SOCKETPAIR - do_rawlog(LT_ERR, "Accepted info slave from unix-domain socket"); -#else - if (getnameinfo(&addr.addr, addr_len, NULL, 0, port, sizeof port, - NI_NUMERICHOST | NI_NUMERICSERV) != 0) { - perror("getting info slave port number"); - } else { - do_rawlog(LT_ERR, "Accepted info slave from port %s", port); - } -#endif - for (j = 0; j < maxd; j++) - if (FD_ISSET(j, &info_pending)) - query_info_slave(j); - if (info_slave >= maxd) - maxd = info_slave + 1; -} - -static void -query_info_slave(int fd) -{ - int size, slen; - socklen_t llen, rlen; - static char buf[1024]; /* overkill */ - union sockaddr_u laddr, raddr; - char *bp; - struct hostname_info *hi; - struct iovec dat[6]; - - FD_SET(fd, &info_pending); - info_queue_time = mudtime; - - if (info_slave_state != 2) { - make_info_slave(); - return; - } - - /* cleanup for truncated packet */ - size = info_query_spill; - memset(buf, 0, size); - info_query_spill = 0; - dat[0].iov_base = buf; - dat[0].iov_len = size; - - rlen = MAXSOCKADDR; - if (getpeername(fd, (struct sockaddr *) raddr.data, &rlen) < 0) { - perror("socket peer vanished"); - shutdown(fd, 2); - closesocket(fd); - FD_CLR(fd, &info_pending); - return; - } - - /* Check for forbidden sites before bothering with ident */ - bp = buf; - hi = ip_convert(&raddr.addr, rlen); - safe_str(hi ? hi->hostname : "Not found", buf, &bp); - *bp = '\0'; - if (Forbidden_Site(buf)) { - char port[NI_MAXSERV]; - if (getnameinfo(&raddr.addr, rlen, NULL, 0, port, sizeof port, - NI_NUMERICHOST | NI_NUMERICSERV) != 0) - perror("getting remote port number"); - else { - if (!Deny_Silent_Site(buf, AMBIGUOUS)) { - do_log(LT_CONN, 0, 0, T("[%d/%s] Refused connection (remote port %s)"), - fd, buf, port); - } - } - shutdown(fd, 2); - closesocket(fd); - FD_CLR(fd, &info_pending); - return; - } - - /* Packet format: SIZESTRUCT for remote address, SIZE STRUCT for - * local address, FD. We use writev() to make the packet format - * explicit to the reader. */ - dat[1].iov_base = (char *) &rlen; - dat[1].iov_len = sizeof rlen; - dat[2].iov_base = (char *) &raddr.addr; - dat[2].iov_len = rlen; - - llen = MAXSOCKADDR; - if (getsockname(fd, (struct sockaddr *) laddr.data, &llen) < 0) { - perror("socket self vanished"); - closesocket(fd); - FD_CLR(fd, &info_pending); - return; - } - - dat[3].iov_base = (char *) &llen; - dat[3].iov_len = sizeof llen; - dat[4].iov_base = (char *) &laddr.addr; - dat[4].iov_len = llen; - dat[5].iov_base = (char *) &fd; - dat[5].iov_len = sizeof fd; - size = dat[0].iov_len + dat[1].iov_len + dat[2].iov_len + dat[3].iov_len - + dat[4].iov_len + dat[5].iov_len; - slen = writev(info_slave, dat, 6); - if (slen < 0) { - perror("info slave query: write error"); - if (errno != EWOULDBLOCK) - make_info_slave(); - return; - } else if (slen < size) { - /* drop partial packet on floor. cleanup later. */ - perror("info slave query: partial packet"); - info_query_spill = size - slen; - } -} - -static void -reap_info_slave(void) -{ - int fd, len, size; - static char buf[10000]; /* overkill */ - char *bp, *bp2; - struct iovec dat[2]; - - if (info_slave_state != 2) { - make_info_slave(); - return; - } - - if (info_reap_spill) { - /* clean up some mess */ - len = read(info_slave, buf, info_reap_spill); - if (len < 1) { - /* crap. lost the slave. */ - perror("info slave reap spill"); - make_info_slave(); - return; - } - info_reap_spill -= len; - if (info_reap_spill) - /* can't read enough, come back later */ - return; - } - for (;;) { - /* Packet format: FD, STRLEN, STR. We use readv() to cut down on - the number of read() system calls. */ - /* grab the fd and string length */ - dat[0].iov_base = (char *) &fd; - dat[0].iov_len = sizeof fd; - dat[1].iov_base = (char *) &size; - dat[1].iov_len = sizeof size; - len = readv(info_slave, dat, 2); - if (len < 0 && errno == EWOULDBLOCK) - /* got all the data */ - return; - if (len < (int) (sizeof fd + sizeof size)) { - /* we're hosed now */ - perror("info slave reap reading fd and hostname length"); - make_info_slave(); - return; - } - if (size < 0 || size > (int) sizeof buf) { - perror("info slave real size"); - make_info_slave(); - return; - } - - /* grab the actual string */ - len = read(info_slave, buf, size); - - if (len < 0) { - /* crap. lost the slave. */ - perror("info slave reap string"); - make_info_slave(); - return; - } - buf[len] = '\0'; - if (len < size) { - /* crap... lost some. clean up the mess and requery */ - info_reap_spill = size - len; - query_info_slave(fd); - return; - } - /* okay, now we have some info! */ - if (!FD_ISSET(fd, &info_pending)) - /* got a bloody duplicate */ - return; - FD_CLR(fd, &info_pending); - /* buf ideally contains ipaddr^local port^ident-info */ - bp = NULL; - if ((bp2 = strchr(buf, '^'))) { - *bp2++ = '\0'; - /* buf is ip addr, bp is local port^ident info */ - if ((bp = strchr(bp2, '^'))) - *bp++ = '\0'; - } - /* Now, either buf = ipaddr, bp2 = port, bp = ident info, - * or buf = ipaddr, bp2 = port - */ - if (Forbidden_Site(buf) || (bp && Forbidden_Site(bp))) { - if (!Deny_Silent_Site(buf, AMBIGUOUS) || !Deny_Silent_Site(bp, AMBIGUOUS)) { - do_log(LT_CONN, 0, 0, T("[%d/%s/%s] Refused connection."), fd, - bp ? bp : "", buf); - } - shutdown(fd, 2); - closesocket(fd); - return; - } - do_log(LT_CONN, 0, 0, T("[%d/%s/%s] Connection opened."), fd, - bp ? bp : "", buf); - set_keepalive(fd); - (void) initializesock(fd, bp ? bp : buf, buf, (atoi(bp2) == SSLPORT)); - } -} - -/** Kill the info_slave process, typically at shutdown. - */ -void -kill_info_slave(void) -{ - WAIT_TYPE my_stat; - Pid_t pid; - struct timeval pad; - - if (info_slave_state != 0) { - if (info_slave_pid > 0) { - do_rawlog(LT_ERR, "kill: killing info_slave_pid %d", info_slave_pid); - - block_a_signal(SIGCHLD); - - closesocket(info_slave); - kill(info_slave_pid, 15); - /* Have to wait long enough for the info_slave to actually - die. This will hopefully be enough time. */ - pad.tv_sec = 0; - pad.tv_usec = 100; - select(0, NULL, NULL, NULL, &pad); - -#ifdef HAS_WAITPID - pid = waitpid(info_slave_pid, &my_stat, WNOHANG); -#else - pid = wait3(&my_stat, WNOHANG, 0); + d->ssl = NULL; + d->ssl_state = 0; #endif - info_slave_pid = -1; - unblock_a_signal(SIGCHLD); +#endif + im_insert(descs_by_fd, d->descriptor, d); + if (descriptor_list) + descriptor_list->prev = d; + d->next = descriptor_list; + d->prev = NULL; + descriptor_list = d; + d->width = 78; + d->height = 24; +#ifndef COMPILE_CONSOLE +#ifdef HAS_OPENSSL + if (use_ssl && sslsock) { + d->ssl = ssl_listen(d->descriptor, &d->ssl_state); + if (d->ssl_state < 0) { + /* Error we can't handle */ + ssl_close_connection(d->ssl); + d->ssl = NULL; + d->ssl_state = 0; } - info_slave_state = 0; } -} #endif + test_telnet(d); #endif /* COMPILE_CONSOLE */ + welcome_user(d); + for(n = 0; n < MAX_SNOOPS; n++) + d->snooper[n] = -1; + return d; +} +/* TODO: Build back in COMPILE_CONSOLE define in here */ /** Flush pending output for a descriptor. * This function actually sends the queued output over the descriptor's @@ -2215,7 +1816,6 @@ process_output(DESC *d) { struct text_block **qp, *cur; int cnt; -#ifndef COMPILE_CONSOLE #ifdef HAS_OPENSSL int input_ready = 0; #endif @@ -2254,6 +1854,15 @@ process_output(DESC *d) * We need to know if the descriptor is waiting on input, though. * So let's find out */ + +#ifdef HAVE_POLL + struct pollfd p; + + p.fd = d->descriptor; + p.events = POLLIN; + p.revents = 0; + input_ready = poll(&p, 1, 0); +#else struct timeval pad; fd_set input_set; @@ -2262,76 +1871,143 @@ process_output(DESC *d) FD_ZERO(&input_set); FD_SET(d->descriptor, &input_set); input_ready = select(d->descriptor + 1, &input_set, NULL, NULL, &pad); +#endif if (input_ready < 0) { /* Well, shoot, we have no idea. Guess and proceed. */ - perror("select in process_output"); + penn_perror("select in process_output"); input_ready = 0; } } #endif -#endif /* COMPILE_CONSOLE */ for (qp = &d->output.head; ((cur = *qp) != NULL);) { -#ifdef COMPILE_CONSOLE - if (d->descriptor == 0) - cnt = write(STDOUT_FILENO, cur->start, cur->nchars); - else -#else /* COMPILE_CONSOLE */ -#ifdef HAS_OPENSSL - if (d->ssl) { +#ifdef HAVE_WRITEV + if (cur->nxt +#ifdef HAVE_SSL + && !d->ssl +#endif + ) { + /* If there's more than one pending block, try to send up to 10 + at once with writev(). Doesn't work for SSL connections, and + if there's only one block waiting to go out, just use + send(). */ + struct iovec lines[10]; + struct text_block *block = cur, *next = NULL; + int n; cnt = 0; - d->ssl_state = ssl_write(d->ssl, d->ssl_state, input_ready, 1, cur->start, - cur->nchars, &cnt); - if (ssl_want_write(d->ssl_state)) - return 1; /* Need to retry */ - } else { + for (n = 0; block && n < 10; block = block->nxt) { + lines[n].iov_base = block->start; + lines[n].iov_len = block->nchars; + cnt += block->nchars; + n += 1; + } +#ifdef DEBUG + do_rawlog(LT_TRACE, "Sending %d bytes in %d blocks to socket %d", + cnt, n, d->descriptor); +#endif + cnt = writev(d->descriptor, lines, n); +#ifdef DEBUG + do_rawlog(LT_TRACE, "writev() returned %d", cnt); #endif -#endif /* COMPILE_CONSOLE */ - cnt = send(d->descriptor, cur->start, cur->nchars, 0); if (cnt < 0) { #ifdef WIN32 if (cnt == SOCKET_ERROR && WSAGetLastError() == WSAEWOULDBLOCK) #else #ifdef EAGAIN - if ((errno == EWOULDBLOCK) || (errno == EAGAIN)) + if ((errno == EWOULDBLOCK) || (errno == EAGAIN) || errno == EINTR) #else - if (errno == EWOULDBLOCK) + if (errno == EWOULDBLOCK || errno = EINTR) #endif #endif return 1; return 0; } -#ifndef COMPILE_CONSOLE + + d->output_size -= cnt; + d->output_chars += cnt; + + for (block = cur; block && cnt > 0; block = next) { + next = block->nxt; + if (cnt >= block->nchars) { + if (!block->nxt) + d->output.tail = qp; + *qp = block->nxt; + cnt -= block->nchars; +#ifdef DEBUG + do_rawlog(LT_TRACE, "free_text_block(%p) at writev", (void *) block); +#endif + free_text_block(block); + } else { +#ifdef DEBUG + do_rawlog(LT_TRACE, + "Incomplete write of block. nchars = %d, cnt = %d", + block->nchars, cnt); +#endif + block->nchars -= cnt; + block->start += cnt; + break; + } + } + } else { +#endif /* HAVE_WRITEV */ #ifdef HAS_OPENSSL - } + if (d->ssl) { + cnt = 0; + d->ssl_state = + ssl_write(d->ssl, d->ssl_state, input_ready, 1, cur->start, + cur->nchars, &cnt); + if (ssl_want_write(d->ssl_state)) + return 1; /* Need to retry */ + } else +#endif /* HAS_OPENSSL */ + { + cnt = send(d->descriptor, cur->start, cur->nchars, 0); + if (cnt < 0) { +#ifdef WIN32 + if (cnt == SOCKET_ERROR && WSAGetLastError() == WSAEWOULDBLOCK) +#else +#ifdef EAGAIN + if ((errno == EWOULDBLOCK) || (errno == EAGAIN) || errno == EINTR) +#else + if (errno == EWOULDBLOCK || errno == EINTR) #endif #endif - d->output_size -= cnt; - d->output_chars += cnt; - if (cnt == cur->nchars) { - if (!cur->nxt) - d->output.tail = qp; - *qp = cur->nxt; + return 1; + return 0; + } + } + d->output_size -= cnt; + d->output_chars += cnt; + if (cnt == cur->nchars) { + if (!cur->nxt) + d->output.tail = qp; + *qp = cur->nxt; #ifdef DEBUG - do_rawlog(LT_ERR, "free_text_block(0x%x) at 2.", cur); + do_rawlog(LT_TRACE, "free_text_block(%p) at 2.", (void *) cur); #endif /* DEBUG */ - free_text_block(cur); - continue; /* do not adv ptr */ + free_text_block(cur); + continue; /* do not adv ptr */ + } + cur->nchars -= cnt; + cur->start += cnt; + break; +#ifdef HAVE_WRITEV } - cur->nchars -= cnt; - cur->start += cnt; - break; +#endif } return 1; } + static void welcome_user(DESC *d) { + /* TODO: Add MUDURL */ if (SUPPORT_PUEBLO && !(d->conn_flags & CONN_HTML)) - queue_newwrite(d, (unsigned char *) PUEBLO_HELLO, strlen(PUEBLO_HELLO)); + queue_newwrite(d, (unsigned const char *) PUEBLO_HELLO, strlen(PUEBLO_HELLO)); fcache_dump(d, fcache.connect_fcache, NULL); + /* TODO: Add MUDURL */ } static void @@ -2366,8 +2042,8 @@ setup_telnet(DESC *d) /* IAC DO NAWS IAC DO TERMINAL-TYPE */ unsigned char extra_options[6] = "\xFF\xFD\x1F" "\xFF\xFD\x18"; d->conn_flags &= ~CONN_TELNET_QUERY; - do_log(LT_CONN, 0, 0, T("[%d/%s/%s] Switching to Telnet mode."), - d->descriptor, d->addr, d->ip); + do_rawlog(LT_CONN, T("[%d/%s/%s] Switching to Telnet mode."), + d->descriptor, d->addr, d->ip); queue_newwrite(d, extra_options, 6); process_output(d); } @@ -2501,6 +2177,7 @@ handle_telnet(DESC *d, unsigned char **q, unsigned char *qend) #ifdef DEBUG_TELNET fprintf(stderr, "Got IAC NOP\n"); #endif + *q += 1; break; case AYT: /* Are you there? */ if (*q >= qend) @@ -2516,7 +2193,7 @@ handle_telnet(DESC *d, unsigned char **q, unsigned char *qend) setup_telnet(d); if (*q >= qend) return -1; - (*q)++; + *q += 1; if (**q == TN_LINEMODE) { /* Set up our preferred linemode options. */ @@ -2589,9 +2266,7 @@ process_input_helper(DESC *d, char *tbuf1, int got) unsigned char *p, *pend, *q, *qend; if (!d->raw_input) { - d->raw_input = - (unsigned char *) mush_malloc(sizeof(char) * MAX_COMMAND_LEN, - "descriptor_raw_input"); + d->raw_input = mush_malloc(MAX_COMMAND_LEN, "descriptor_raw_input"); if (!d->raw_input) mush_panic("Out of memory"); d->raw_input_at = d->raw_input; @@ -2734,7 +2409,7 @@ static void set_userstring(unsigned char **userstring, const char *command) { if (*userstring) { - mush_free((Malloc_t) *userstring, "userstring"); + mush_free((Malloc_t) * userstring, "userstring"); *userstring = NULL; } while (*command && isspace((unsigned char) *command)) @@ -2783,7 +2458,7 @@ process_commands(void) cdesc->input.tail = &cdesc->input.head; if (t) { #ifdef DEBUG - do_rawlog(LT_ERR, "free_text_block(0x%x) at 5.", t); + do_rawlog(LT_TRACE, "free_text_block(%p) at 5.", (void *) t); #endif /* DEBUG */ free_text_block(t); } @@ -2856,10 +2531,11 @@ do_command(DESC *d, char *command) && !strncmp(command, PUEBLO_COMMAND, strlen(PUEBLO_COMMAND))) { parse_puebloclient(d, command); if (!(d->conn_flags & CONN_HTML)) { - queue_newwrite(d, (unsigned char *) PUEBLO_SEND, strlen(PUEBLO_SEND)); + queue_newwrite(d, (unsigned const char *) PUEBLO_SEND, + strlen(PUEBLO_SEND)); process_output(d); - do_log(LT_CONN, 0, 0, T("[%d/%s/%s] Switching to Pueblo mode."), - d->descriptor, d->addr, d->ip); + do_rawlog(LT_CONN, T("[%d/%s/%s] Switching to Pueblo mode."), + d->descriptor, d->addr, d->ip); d->conn_flags |= CONN_HTML; if (!d->connected) welcome_user(d); @@ -2868,8 +2544,8 @@ do_command(DESC *d, char *command) if (d->connected) { send_prefix(d); global_eval_context.cplr = d->player; - strcpy(global_eval_context.ccom, command); - strcpy(global_eval_context.ucom, ""); + mush_strncpy(global_eval_context.ccom, command, BUFFER_LEN); + global_eval_context.ucom[0] = '\0'; /* Clear %0-%9 and r(0) - r(9) */ for (j = 0; j < 10; j++) @@ -2902,8 +2578,7 @@ parse_puebloclient(DESC *d, char *command) if ((end = strchr(p, '"'))) { if ((end > p) && ((end - p) <= PUEBLO_CHECKSUM_LEN)) { /* Got it! */ - strncpy(d->checksum, p, end - p); - d->checksum[end - p] = '\0'; + mush_strncpy(d->checksum, p, end - p); } } } @@ -2954,9 +2629,6 @@ dump_messages(DESC *d, dbref player, int isnew) return 0; } } -#ifdef USE_MAILER - d->mailp = find_exact_starting_point(player); -#endif /* check to see if this is a reconnect and also set DARK status */ is_hidden = Can_Hide(player) && Dark(player); @@ -3013,10 +2685,10 @@ check_connect(DESC *d, const char *msg) if ((player = connect_player(user, password, d->addr, d->ip, errbuf)) == NOTHING) { queue_string_eol(d, errbuf); - do_log(LT_CONN, 0, 0, T("[%d/%s/%s] Failed connect to '%s'."), + do_rawlog(LT_CONN, T("[%d/%s/%s] Failed connect to '%s'."), d->descriptor, d->addr, d->ip, user); } else { - do_log(LT_CONN, 0, 0, T("[%d/%s/%s] Connected to %s(#%d) in %s(#%d)"), + do_rawlog(LT_CONN, T("[%d/%s/%s] Connected to %s(#%d) in %s(#%d)"), d->descriptor, d->addr, d->ip, Name(player), player, Name(Location(player)), Location(player)); /* Check if we're fake siting this guy.. */ @@ -3036,13 +2708,13 @@ check_connect(DESC *d, const char *msg) if ((player = connect_player(user, password, d->addr, d->ip, errbuf)) == NOTHING) { queue_string_eol(d, errbuf); - do_log(LT_CONN, 0, 0, T("[%d/%s/%s] Failed connect to '%s'."), - d->descriptor, d->addr, d->ip, user); + do_rawlog(LT_CONN, T("[%d/%s/%s] Failed connect to '%s'."), + d->descriptor, d->addr, d->ip, user); } else { - do_log(LT_CONN, 0, 0, - T("[%d/%s/%s] Connected dark to %s(#%d) in %s(#%d)"), - d->descriptor, d->addr, d->ip, Name(player), player, - Name(Location(player)), Location(player)); + do_rawlog(LT_CONN, + T("[%d/%s/%s] Connected dark to %s(#%d) in %s(#%d)"), + d->descriptor, d->addr, d->ip, Name(player), player, + Name(Location(player)), Location(player)); /* Set player dark */ d->connected = 1; d->player = player; @@ -3057,12 +2729,12 @@ check_connect(DESC *d, const char *msg) if ((player = connect_player(user, password, d->addr, d->ip, errbuf)) == NOTHING) { queue_string_eol(d, errbuf); - do_log(LT_CONN, 0, 0, T("[%d/%s/%s] Failed connect to '%s'."), - d->descriptor, d->addr, d->ip, user); + do_rawlog(LT_CONN, T("[%d/%s/%s] Failed connect to '%s'."), + d->descriptor, d->addr, d->ip, user); } else { - do_log(LT_CONN, 0, 0, T("[%d/%s/%s] Connected to %s(#%d) in %s(#%d)"), - d->descriptor, d->addr, d->ip, Name(player), player, - Name(Location(player)), Location(player)); + do_rawlog(LT_CONN, T("[%d/%s/%s] Connected to %s(#%d) in %s(#%d)"), + d->descriptor, d->addr, d->ip, Name(player), player, + Name(Location(player)), Location(player)); /* Set player !dark */ d->connected = 1; d->player = player; @@ -3077,13 +2749,13 @@ check_connect(DESC *d, const char *msg) if ((player = connect_player(user, password, d->addr, d->ip, errbuf)) == NOTHING) { queue_string_eol(d, errbuf); - do_log(LT_CONN, 0, 0, T("[%d/%s/%s] Failed connect to '%s'."), - d->descriptor, d->addr, d->ip, user); + do_rawlog(LT_CONN, T("[%d/%s/%s] Failed connect to '%s'."), + d->descriptor, d->addr, d->ip, user); } else { - do_log(LT_CONN, 0, 0, - T("[%d/%s/%s] Connected hidden to %s(#%d) in %s(#%d)"), - d->descriptor, d->addr, d->ip, Name(player), player, - Name(Location(player)), Location(player)); + do_rawlog(LT_CONN, + T("[%d/%s/%s] Connected hidden to %s(#%d) in %s(#%d)"), + d->descriptor, d->addr, d->ip, Name(player), player, + Name(Location(player)), Location(player)); /* Set player hidden */ d->connected = 1; d->player = player; @@ -3100,8 +2772,8 @@ check_connect(DESC *d, const char *msg) fcache_dump(d, fcache.register_fcache, NULL); if (!Deny_Silent_Site(d->addr, AMBIGUOUS) && !Deny_Silent_Site(d->ip, AMBIGUOUS)) { - do_log(LT_CONN, 0, 0, T("[%d/%s/%s] Refused create for '%s'."), - d->descriptor, d->addr, d->ip, user); + do_rawlog(LT_CONN, T("[%d/%s/%s] Refused create for '%s'."), + d->descriptor, d->addr, d->ip, user); } return 0; } @@ -3124,17 +2796,17 @@ check_connect(DESC *d, const char *msg) player = create_player(user, password, d->addr, d->ip); if (player == NOTHING) { queue_string_eol(d, T(create_fail)); - do_log(LT_CONN, 0, 0, - T("[%d/%s/%s] Failed create for '%s' (bad name)."), - d->descriptor, d->addr, d->ip, user); + do_rawlog(LT_CONN, + T("[%d/%s/%s] Failed create for '%s' (bad name)."), + d->descriptor, d->addr, d->ip, user); } else if (player == AMBIGUOUS) { queue_string_eol(d, T(password_fail)); - do_log(LT_CONN, 0, 0, - T("[%d/%s/%s] Failed create for '%s' (bad password)."), - d->descriptor, d->addr, d->ip, user); + do_rawlog(LT_CONN, + T("[%d/%s/%s] Failed create for '%s' (bad password)."), + d->descriptor, d->addr, d->ip, user); } else { - do_log(LT_CONN, 0, 0, "[%d/%s/%s] Created %s(#%d)", - d->descriptor, d->addr, d->ip, Name(player), player); + do_rawlog(LT_CONN, "[%d/%s/%s] Created %s(#%d)", + d->descriptor, d->addr, d->ip, Name(player), player); if ((dump_messages(d, player, 1)) == 0) { d->connected = 2; return 0; @@ -3146,9 +2818,9 @@ check_connect(DESC *d, const char *msg) fcache_dump(d, fcache.register_fcache, NULL); if (!Deny_Silent_Site(d->addr, AMBIGUOUS) && !Deny_Silent_Site(d->ip, AMBIGUOUS)) { - do_log(LT_CONN, 0, 0, - T("[%d/%s/%s] Refused registration (bad site) for '%s'."), - d->descriptor, d->addr, d->ip, user); + do_rawlog(LT_CONN, + T("[%d/%s/%s] Refused registration (bad site) for '%s'."), + d->descriptor, d->addr, d->ip, user); } return 0; } @@ -3162,12 +2834,12 @@ check_connect(DESC *d, const char *msg) if ((player = email_register_player(user, password, d->addr, d->ip)) == NOTHING) { queue_string_eol(d, T(register_fail)); - do_log(LT_CONN, 0, 0, T("[%d/%s/%s] Failed registration for '%s'."), - d->descriptor, d->addr, d->ip, user); + do_rawlog(LT_CONN, T("[%d/%s/%s] Failed registration for '%s'."), + d->descriptor, d->addr, d->ip, user); } else { queue_string_eol(d, T(register_success)); - do_log(LT_CONN, 0, 0, "[%d/%s/%s] Registered %s(#%d) to %s", - d->descriptor, d->addr, d->ip, Name(player), player, password); + do_rawlog(LT_CONN, T("[%d/%s/%s] Registered %s(#%d) to %s"), + d->descriptor, d->addr, d->ip, Name(player), player, password); } /* Whether it succeeds or fails, leave them connected */ @@ -3233,34 +2905,50 @@ static void close_sockets(void) { DESC *d, *dnext; + const char *shutmsg; + int shutlen; + + shutmsg = T(shutdown_message); + shutlen = strlen(shutmsg); for (d = descriptor_list; d; d = dnext) { dnext = d->next; -#ifdef COMPILE_CONSOLE - if(d->descriptor == 0) { - write(STDOUT_FILENO, T(shutdown_message), strlen(T(shutdown_message))); - write(STDOUT_FILENO, "\r\n", 2); - } else { - send(d->descriptor, T(shutdown_message), strlen(T(shutdown_message)), 0); - send(d->descriptor, "\r\n", 2, 0); - if (shutdown(d->descriptor, 2) < 0) - perror("shutdown"); - closesocket(d->descriptor); - } -#else /* COMPILE_CONSOLE */ - send(d->descriptor, T(shutdown_message), strlen(T(shutdown_message)), 0); - send(d->descriptor, "\r\n", 2, 0); #ifdef HAS_OPENSSL - if (d->ssl) { + if (!d->ssl) { +#endif +#ifdef HAVE_WRITEV + struct iovec byebye[2]; + byebye[0].iov_base = (char *) shutmsg; + byebye[0].iov_len = shutlen; + byebye[1].iov_base = (char *) "\r\n"; + byebye[1].iov_len = 2; + writev(d->descriptor, byebye, 2); +#else + send(d->descriptor, shutmsg, shutlen, 0); + send(d->descriptor, (char *) "\r\n", 2, 0); +#endif +#ifdef HAS_OPENSSL + } else { + int offset; + offset = 0; + ssl_write(d->ssl, d->ssl_state, 0, 1, (uint8_t *) shutmsg, + shutlen, &offset); + offset = 0; + ssl_write(d->ssl, d->ssl_state, 0, 1, (uint8_t *) "\r\n", 2, &offset); + const char *shutmsg = T(shutdown_message); + offset = 0; + ssl_write(d->ssl, d->ssl_state, 0, 1, (uint8_t *) shutmsg, + strlen(shutmsg), &offset); + offset = 0; + ssl_write(d->ssl, d->ssl_state, 0, 1, (uint8_t *) "\r\n", 2, &offset); ssl_close_connection(d->ssl); d->ssl = NULL; d->ssl_state = 0; } #endif if (shutdown(d->descriptor, 2) < 0) - perror("shutdown"); + penn_perror("shutdown"); closesocket(d->descriptor); -#endif /* COMPILE_CONSOLE */ } } @@ -3270,6 +2958,9 @@ void emergency_shutdown(void) { close_sockets(); +#ifdef INFO_SLAVE + kill_info_slave(); +#endif } /** Disconnect a descriptor. @@ -3470,26 +3161,20 @@ void reaper(int sig __attribute__ ((__unused__))) { WAIT_TYPE my_stat; - Pid_t pid; + pid_t pid; -#ifdef HAS_WAITPID - while ((pid = waitpid(-1, &my_stat, WNOHANG)) > 0) -#else - while ((pid = wait3(&my_stat, WNOHANG, 0)) > 0) -#endif - { + while ((pid = mush_wait(-1, &my_stat, WNOHANG)) > 0) { #ifndef COMPILE_CONSOLE #ifdef INFO_SLAVE if (info_slave_pid > -1 && pid == info_slave_pid) { do_rawlog(LT_ERR, T("info_slave on pid %d exited!"), pid); - info_slave_state = 0; + slave_error = info_slave_pid; + info_slave_state = INFO_SLAVE_DOWN; info_slave_pid = -1; - slave_error = pid; } else #endif #endif if (forked_dump_pid > -1 && pid == forked_dump_pid) { - /* Most failures are handled by the forked mush already */ dump_error = forked_dump_pid; dump_status = my_stat; forked_dump_pid = -1; @@ -3542,7 +3227,7 @@ dump_users(DESC *call_by, char *match, int doing) int csite; if (!GoodObject(call_by->player)) { - do_log(LT_ERR, 0, 0, T("Bogus caller #%d of dump_users"), call_by->player); + do_rawlog(LT_ERR, T("Bogus caller #%d of dump_users"), call_by->player); return; } while (*match && *match == ' ') @@ -3554,28 +3239,28 @@ dump_users(DESC *call_by, char *match, int doing) */ if (SUPPORT_PUEBLO && (call_by->conn_flags & CONN_HTML)) { - queue_newwrite(call_by, (unsigned char *) "", 19); - queue_newwrite(call_by, (unsigned char *) "
", 5);
+    queue_newwrite(call_by, (const unsigned char *) "", 19);
+    queue_newwrite(call_by, (const unsigned char *) "
", 5);
   }
 
   if ((doing == 1) || !call_by->player || !Priv_Who(call_by->player)) {
     if (poll_msg[0] == '\0')
       strcpy(poll_msg, "Doing");
     if (ShowAnsi(call_by->player))
-      sprintf(tbuf2, "%s%-16s %4s %10s %6s  %s%s\n", ANSI_HILITE,
-              T("Player Name"), T("Aff"), T("On For"), T("Idle"), poll_msg, ANSI_NORMAL);
+      snprintf(tbuf2, BUFFER_LEN, "%s%-16s %4s %10s %6s  %s%s\n", ANSI_HILITE,
+              T("Player Name"), T("Aff"), T("On For"), T("Idle"), poll_msg, ANSI_END);
     else
-      sprintf(tbuf2, "%-16s %4s %10s %6s  %s\n",
+      snprintf(tbuf2, BUFFER_LEN, "%-16s %4s %10s %6s  %s\n",
               T("Player Name"), T("Aff"), T("On For"), T("Idle"), poll_msg);
     queue_string(call_by, tbuf2);
   } else if (doing == 2) {
-    sprintf(tbuf2, "%s%-16s %6s %9s %5s %5s Des  Sent    Recv  Pend%s\n", ShowAnsi(call_by->player) ? ANSI_HILITE :
+    snprintf(tbuf2, BUFFER_LEN, "%s%-16s %6s %9s %5s %5s Des  Sent    Recv  Pend%s\n", ShowAnsi(call_by->player) ? ANSI_HILITE :
                     "", T("Player Name"), T("Loc #"), T("On For"), T("Idle"), T("Cmds"),
-                    ShowAnsi(call_by->player) ? ANSI_NORMAL : "");
+                    ShowAnsi(call_by->player) ? ANSI_END : "");
     queue_string(call_by, tbuf2);
   } else {
-    sprintf(tbuf2, "%s%-16s %6s %9s %5s %5s Des   Host%s\n", ShowAnsi(call_by->player) ? ANSI_HILITE : "",
-            T("Player Name"), T("Loc #"), T("On For"), T("Idle"), T("Cmds"), ShowAnsi(call_by->player) ? ANSI_NORMAL : "");
+    snprintf(tbuf2, BUFFER_LEN,  "%s%-16s %6s %9s %5s %5s Des   Host%s\n", ShowAnsi(call_by->player) ? ANSI_HILITE : "",
+            T("Player Name"), T("Loc #"), T("On For"), T("Idle"), T("Cmds"), ShowAnsi(call_by->player) ? ANSI_END : "");
     queue_string(call_by, tbuf2);
   }
 
@@ -3646,7 +3331,7 @@ dump_users(DESC *call_by, char *match, int doing)
         if (!Hidden(d)
             || call_by->player == d->player ||
             (call_by->player && Priv_Who(call_by->player) && (doing))) {
-          sprintf(tbuf1, "%-16s %4s %10s   %4s%c %s", tprintf("%s%s", Name(d->player), InProg(d->player) ? "(P)" : ""), empabb(d->player),
+          snprintf(tbuf1, BUFFER_LEN, "%-16s %4s %10s   %4s%c %s", tprintf("%s%s", Name(d->player), InProg(d->player) ? "(P)" : ""), empabb(d->player),
                   time_format_1(now - d->connected_at),
                   time_format_2(now - d->last_time),
                   (Dark(d->player) ? 'D' : (Hidden(d) ? 'H' : ' '))
@@ -3657,14 +3342,14 @@ dump_users(DESC *call_by, char *match, int doing)
       if (!Hidden(d) || (call_by->player && Priv_Who(call_by->player))) {
 #ifdef COLOREDWHO
         if(ShowAnsiColor(call_by->player))
-                queue_string(call_by, tprintf("%s%s%s%s%s", ANSI_NORMAL, (tcount % 2 ?  "" : ANSI_HILITE), 
+                queue_string(call_by, tprintf("%s%s%s%s%s", ANSI_END, (tcount % 2 ?  "" : ANSI_HILITE), 
                                         (tcount % 2 ? ANSI_CYAN : ANSI_WHITE),
                                         tbuf1, ANSI_NORMAL));
 
         else 
 #endif
                 queue_string(call_by, tbuf1);
-        queue_newwrite(call_by, (unsigned char *) "\r\n", 2);
+        queue_newwrite(call_by, (const unsigned char *) "\r\n", 2);
       }
     } else if (call_by->player && Priv_Who(call_by->player) && doing != 1
                && (!match || !*match)) {
@@ -3673,7 +3358,7 @@ dump_users(DESC *call_by, char *match, int doing)
 #endif
       if (doing == 0) {
         /* Privileged WHO for non-logged in connections */
-        sprintf(tbuf1, "%-16s %6s %9s %5s  %4d %3d%c  %s", T("Connecting..."),
+        snprintf(tbuf1, BUFFER_LEN, "%-16s %6s %9s %5s  %4d %3d%c  %s", T("Connecting..."),
                 "#-1",
                 time_format_1(now - d->connected_at),
                 time_format_2(now - d->last_time), d->cmds, d->descriptor,
@@ -3691,7 +3376,7 @@ dump_users(DESC *call_by, char *match, int doing)
         tbuf1[78] = '\0';
       } else {
         /* SESSION for non-logged in connections */
-        sprintf(tbuf1, "%-16s %5s %9s %5s %5d %3d%c %5lu %7lu %5d",
+        snprintf(tbuf1, BUFFER_LEN, "%-16s %5s %9s %5s %5d %3d%c %5lu %7lu %5d",
                 T("Connecting..."), "#-1",
                 time_format_1(now - d->connected_at),
                 time_format_2(now - d->last_time), d->cmds, d->descriptor,
@@ -3713,18 +3398,18 @@ dump_users(DESC *call_by, char *match, int doing)
       else 
 #endif
               queue_string(call_by, tbuf1);
-      queue_newwrite(call_by, (unsigned char *) "\r\n", 2);
+      queue_newwrite(call_by, (const unsigned char *) "\r\n", 2);
     }
   }
   switch (count) {
   case 0:
-    strcpy(tbuf1, T("There are no players connected."));
+    mush_strncpy(tbuf1, T("There are no players connected."), BUFFER_LEN);
     break;
   case 1:
-    strcpy(tbuf1, T("There is 1 player connected."));
+    mush_strncpy(tbuf1, T("There is 1 player connected."), BUFFER_LEN);
     break;
   default:
-    sprintf(tbuf1, T("There are %d players connected."), count);
+    snprintf(tbuf1, BUFFER_LEN, T("There are %d players connected."), count);
     break;
   }
 
@@ -3736,10 +3421,10 @@ dump_users(DESC *call_by, char *match, int doing)
 #endif
           queue_string(call_by, tbuf1);
   if (SUPPORT_PUEBLO && (call_by->conn_flags & CONN_HTML)) {
-    queue_newwrite(call_by, (unsigned char *) "\n
\n", 8); - queue_newwrite(call_by, (unsigned char *) "", 23); + queue_newwrite(call_by, (const unsigned char *) "\n
\n", 8); + queue_newwrite(call_by, (const unsigned char *) "", 23); } else - queue_newwrite(call_by, (unsigned char *) "\r\n", 2); + queue_newwrite(call_by, (const unsigned char *) "\r\n", 2); } static const char * @@ -3791,6 +3476,7 @@ announce_connect(dbref player, int isnew, int num) { dbref loc; char tbuf1[BUFFER_LEN]; + char *myenv[2]; dbref zone; dbref obj; int j; @@ -3799,20 +3485,20 @@ announce_connect(dbref player, int isnew, int num) if (isnew) { /* A brand new player created. */ - sprintf(tbuf1, T("%s created."), Name(player)); + snprintf(tbuf1, BUFFER_LEN, T("%s created."), Name(player)); flag_broadcast(0, "MONITOR", "%s %s", T("GAME:"), tbuf1); } /* Redundant, but better for translators */ if (Dark(player)) { - sprintf(tbuf1, (num > 1) ? T("%s has DARK-reconnected.") : - T("%s has DARK-connected."), Name(player)); + snprintf(tbuf1, BUFFER_LEN, (num > 1) ? T("%s has DARK-reconnected.") : + T("%s has DARK-connected."), Name(player)); } else if (hidden(player)) { - sprintf(tbuf1, (num > 1) ? T("%s has HIDDEN-reconnected.") : - T("%s has HIDDEN-connected."), Name(player)); + snprintf(tbuf1, BUFFER_LEN, (num > 1) ? T("%s has HIDDEN-reconnected.") : + T("%s has HIDDEN-connected."), Name(player)); } else { - sprintf(tbuf1, (num > 1) ? T("%s has reconnected.") : - T("%s has connected."), Name(player)); + snprintf(tbuf1, BUFFER_LEN, (num > 1) ? T("%s has reconnected.") : + T("%s has connected."), Name(player)); } /* send out messages */ @@ -3850,6 +3536,14 @@ announce_connect(dbref player, int isnew, int num) global_eval_context.rnxt[j] = NULL; clear_namedregs(&global_eval_context.namedregsnxt); strcpy(global_eval_context.ccom, ""); + /* And then load it up, as follows: + * %0 (unused, reserved for "reason for disconnect") + * %1 (number of connections after connect) + */ + myenv[0] = NULL; + myenv[1] = mush_strdup(unparse_integer(num), "myenv"); + for (j = 0; j < 2; j++) + global_eval_context.wnxt[j] = myenv[j]; /* do the person's personal connect action */ (void) queue_attribute(player, "ACONNECT", player); @@ -3875,15 +3569,21 @@ announce_connect(dbref player, int isnew, int num) } break; default: - do_log(LT_ERR, 0, 0, - T("Invalid zone #%d for %s(#%d) has bad type %d"), zone, - Name(player), player, Typeof(zone)); + do_rawlog(LT_ERR, + T("Invalid zone #%d for %s(#%d) has bad type %d"), zone, + Name(player), player, Typeof(zone)); } } /* now try the master room */ DOLIST(obj, Contents(MASTER_ROOM)) { (void) queue_attribute(obj, "ACONNECT", player); } + for (j = 0; j < 2; j++) + if (myenv[j]) + mush_free(myenv[j], "myenv"); + for (j = 0; j < 10; j++) + global_eval_context.wnxt[j] = NULL; + strcpy(global_eval_context.ccom, ""); } void @@ -3949,8 +3649,7 @@ announce_disconnect(dbref player) } break; default: - do_log(LT_ERR, 0, 0, - T("Invalid zone #%d for %s(#%d) has bad type %d"), zone, + do_rawlog(LT_ERR, T("Invalid zone #%d for %s(#%d) has bad type %d"), zone, Name(player), player, Typeof(zone)); } } @@ -4013,28 +3712,35 @@ announce_disconnect(dbref player) void do_motd(dbref player, enum motd_type key, const char *message) { + const char *what; - if (!Site(player) && key != MOTD_LIST) { + if(key != MOTD_LIST && !Can_Announce(player)) { notify(player, T ("You may get 15 minutes of fame and glory in life, but not right now.")); return; } + + if (!message || !*message) + what = T("cleared"); + else + what = T("set"); + switch (key) { case MOTD_MOTD: - strcpy(cf_motd_msg, message); - notify(player, T("Motd set.")); + mush_strncpy(cf_motd_msg, message, BUFFER_LEN); + notify_format(player, T("Motd %s."), what); break; case MOTD_DOWN: - strcpy(cf_downmotd_msg, message); - notify(player, T("Down motd set.")); + mush_strncpy(cf_downmotd_msg, message, BUFFER_LEN); + notify_format(player, T("Down motd %s."), what); break; case MOTD_FULL: - strcpy(cf_fullmotd_msg, message); - notify(player, T("Full motd set.")); + mush_strncpy(cf_fullmotd_msg, message, BUFFER_LEN); + notify_format(player, T("Full motd %s."), what); break; case MOTD_LIST: - notify_format(player, "MOTD: %s", cf_motd_msg); + notify_format(player, T("MOTD: %s"), cf_motd_msg); if (Site(player)) { notify_format(player, T("Down MOTD: %s"), cf_downmotd_msg); notify_format(player, T("Full MOTD: %s"), cf_fullmotd_msg); @@ -4061,7 +3767,7 @@ do_doing(dbref player, const char *message) notify(player, T("Why would you want to do that?")); return; } - strncpy(buf, remove_markup(message, NULL), DOING_LEN - 1); + mush_strncpy(buf, remove_markup(message, NULL), DOING_LEN); /* now smash undesirable characters and truncate */ for (i = 0; i < DOING_LEN; i++) { @@ -4301,16 +4007,14 @@ lookup_desc(dbref executor, const char *name) /* Given a file descriptor. See-all only. */ if (is_strict_integer(name)) { int fd = parse_integer(name); - DESC_ITER_CONN(d) { - if (d->descriptor == fd) { - if (Priv_Who(executor) || d->player == executor - || (Inherit_Powers(executor) && Priv_Who(Owner(executor)))) - return d; - else - return NULL; - } - } - return NULL; + + d = im_find(descs_by_fd, fd); + if (d && (Priv_Who(executor) || d->player == executor + || (Inherit_Powers(executor) && Priv_Who(Owner(executor))))) + return d; + else + return NULL; + } else { /* Look up player name */ DESC *match = NULL; dbref target = lookup_player(name); @@ -4518,6 +4222,17 @@ FUNCTION(fun_zwho) } } +/* ARGSUSED */ +FUNCTION(fun_player) +{ + /* Gets the player associated with a particular descriptor */ + DESC *d = lookup_desc(executor, args[0]); + if (d) + safe_dbref(d->player, buff, bp); + else + safe_str("#-1", buff, bp); +} + /* ARGSUSED */ FUNCTION(fun_doing) { @@ -4871,7 +4586,7 @@ inactivity_check(void) a telnet-aware client, send a NOP */ if (d->conn_flags & CONN_TELNET && idle_for >= 60 && IS(d->player, TYPE_PLAYER, "KEEPALIVE")) { - const unsigned char nopmsg[2] = { IAC, NOP }; + const uint8_t nopmsg[2] = { IAC, NOP }; queue_newwrite(d, nopmsg, 2); process_output(d); } @@ -4894,9 +4609,9 @@ after_idle_atr_check: else if (!Can_Idle(d->player)) { queue_string(d, T("\n*** Inactivity timeout ***\n")); - do_log(LT_CONN, 0, 0, - T("[%d/%s/%s] Logout by %s(#%d) "), - d->descriptor, d->addr, d->ip, Name(d->player), d->player); + do_rawlog(LT_CONN, + T("[%d/%s/%s] Logout by %s(#%d) "), + d->descriptor, d->addr, d->ip, Name(d->player), d->player); boot_desc(d); } else if (Unfind(d->player)) { @@ -4933,74 +4648,6 @@ hidden(dbref player) } -#ifdef USE_MAILER - -/** Return the mailp of the player closest in db# to player, - * or NULL if there's nobody on-line. - * In the current mail system, mail is stored in a linked list, sorted - * by recipient, which makes the most common operations (listing and reading - * your mail) fast. When a player first connects, we store (on the - * mailp element of their descriptor) a pointer to the beginning of - * their part of the linked list. Rather than search the whole linked - * list to find this location, we look at the mailp's of all the other - * connected players, and find the mailp of the player whose dbref - * is closest to the connecting player, and start our search from that - * point. This scales up nicely - as a mushes get larger, the linked - * list gets larger, but the more people connected at once, the faster - * the search for a newly connecting player's first mail. - * \param player player whose db# we want to get near. - * \return pointer to first mail of connected player with db# closest to - * player. - */ -MAIL * -desc_mail(dbref player) -{ - DESC *d; - int i; - int diff = db_top; - static MAIL *mp; - mp = NULL; - DESC_ITER_CONN(d) { - i = abs(d->player - player); - if (i == 0) - return d->mailp; - if ((i < diff) && d->mailp) { - diff = i; - mp = d->mailp; - } - } - return mp; -} - -/** Set a player's mail position on all their descriptors. - * \param player player to set mail position for. - * \param mp pointer to first mail in their list. - */ -void -desc_mail_set(dbref player, MAIL *mp) -{ - DESC *d; - DESC_ITER_CONN(d) { - if (d->player == player) - d->mailp = mp; - } -} - -/** Clear mail positions on all descriptors. Called from do_mail_nuke(). - */ -void -desc_mail_clear(void) -{ - DESC *d; - DESC_ITER_CONN(d) { - d->mailp = NULL; - } -} - -#endif /* USE_MAILER */ - - - #ifdef SUN_OS /* SunOS's implementation of stdio breaks when you get a file descriptor * greater than 128. Brain damage, brain damage, brain damage! @@ -5337,9 +4984,9 @@ load_reboot_db(void) d->output_suffix = NULL; if (strcmp(temp, "__NONE__")) set_userstring(&d->output_suffix, temp); - strcpy(d->addr, getstring_noalloc(f)); - strcpy(d->ip, getstring_noalloc(f)); - strcpy(d->doing, getstring_noalloc(f)); + mush_strncpy(d->addr, getstring_noalloc(f), 100); + mush_strncpy(d->ip, getstring_noalloc(f), 100); + mush_strncpy(d->doing, getstring_noalloc(f), DOING_LEN); d->conn_flags = getref(f); if (flags & RDBF_SCREENSIZE) { d->width = getref(f); @@ -5382,9 +5029,6 @@ load_reboot_db(void) d->raw_input = NULL; d->raw_input_at = NULL; d->quota = options.starting_quota; -#ifdef USE_MAILER - d->mailp = NULL; -#endif #ifndef COMPILE_CONSOLE #ifdef HAS_OPENSSL d->ssl = NULL; @@ -5408,6 +5052,7 @@ load_reboot_db(void) d->next = descriptor_list; d->prev = NULL; descriptor_list = d; + im_insert(descs_by_fd, d->descriptor, d); if (d->connected && d->player && GoodObject(d->player) && IsPlayer(d->player)) set_flag_internal(d->player, "CONNECTED"); @@ -5442,15 +5087,10 @@ load_reboot_db(void) strcpy(poll_msg, getstring_noalloc(f)); globals.first_start_time = getref(f); globals.reboot_count = getref(f) + 1; -#ifdef USE_MAILER - DESC_ITER_CONN(d) { - d->mailp = find_exact_starting_point(d->player); - } -#endif #ifndef COMPILE_CONSOLE #ifdef HAS_OPENSSL if (SSLPORT) { - sslsock = make_socket(SSLPORT, NULL, NULL, SSL_IP_ADDR); + sslsock = make_socket(SSLPORT, SOCK_STREAM, NULL, SSL_IP_ADDR); ssl_master_socket = ssl_setup_socket(sslsock); if (sslsock >= maxd) maxd = sslsock + 1; @@ -5674,9 +5314,6 @@ COMMAND(cmd_su) { add_to_exit_path(match, player); announce_disconnect(player); match->player = target; -#ifdef USE_MAILER - match->mailp = find_exact_starting_point(target); -#endif is_hidden = Can_Hide(target) && Dark(target); DESC_ITER_CONN(d) if(d->player == player) { @@ -5805,9 +5442,6 @@ static int do_su_exit(DESC *d) { /* Clear path_entry spot */ d->su_exit_path = path_entry->next; mush_free(path_entry, "SU_PATH_ENTRY"); -#ifdef USE_MAILER - d->mailp = find_exact_starting_point(d->player); -#endif is_hidden = Can_Hide(d->player) && Dark(d->player); DESC_ITER_CONN(c) if(c->player == d->player) { @@ -5889,9 +5523,225 @@ do_reboot(dbref player, int flag) MODULE_FUNC_NOARGS(handle, m->handle, "module_shutdown"); end_all_logs(); #ifndef WIN32 - execl("netmush", "netmush", confname, NULL); + { + const char *args[6]; + int n = 0; + + args[n++] = saved_argv[0]; + args[n++] = "--no-session"; + if (pidfile) { + args[n++] = "--pid-file"; + args[n++] = pidfile; + } + args[n++] = confname; + args[n++] = NULL; + + execv(saved_argv[0], (char **) args); + } #else execl("cobramush.exe", "cobramush.exe", "/run", NULL); #endif /* WIN32 */ exit(1); /* Shouldn't ever get here, but just in case... */ } + +/* File modification watching code. Linux-specific for now. + * Future directions include: kqueue() for BSD, fam for linux, irix, others? + * + * The idea to watch help.txt and motd.txt and friends to avoid having + * to do a manual @readcache. Rather than figuring out which exact + * file was changed, just re-read them all on modification of + * any. That will probably change in the future. + */ + +extern HASHTAB help_files; + +static void +reload_files(void) +{ + do_rawlog(LT_TRACE, + "Reloading help indexes and cached files after detecting a change."); + fcache_load(NOTHING); + help_reindex(NOTHING); +} + +#ifdef HAVE_INOTIFY +/* Linux 2.6 and greater inotify() file monitoring interface */ + +static void +watch_files_in(int fd) +{ + int n; + help_file *h; + +#define WATCH(name) do { \ + if (inotify_add_watch(fd, (name), \ + IN_MODIFY | IN_DELETE_SELF | IN_MOVE_SELF) < 0) \ + do_rawlog(LT_TRACE, "file_watch_init:inotify_add_watch(\"%s\"): %s", \ + (name), strerror(errno)); \ + } while (0) + + do_rawlog(LT_TRACE, + "'No such file or directory' errors immediately following are probably harmless."); + for (n = 0; n < 2; n++) { + WATCH(options.connect_file[n]); + WATCH(options.motd_file[n]); + WATCH(options.register_file[n]); + WATCH(options.quit_file[n]); + WATCH(options.down_file[n]); + WATCH(options.full_file[n]); + WATCH(options.guest_file[n]); + } + + for (h = hash_firstentry(&help_files); h; h = hash_nextentry(&help_files)) + WATCH(h->file); + +#undef WATCH +} + +static int +file_watch_init_in(void) +{ + int fd = inotify_init(); + + if (fd < 0) { + penn_perror("file_watch_init:inotify_init"); + return -1; + } + + if (fd >= maxd) + maxd = fd + 1; + + watch_files_in(fd); + + make_nonblocking(fd); + + return fd; +} + +static void +file_watch_event_in(int fd) +{ + struct inotify_event ev; + + while (read(fd, &ev, sizeof ev) > 0) { + if (ev.mask != IN_IGNORED) { + reload_files(); + watch_files_in(fd); + } + } +} + +#elif defined(HAVE_LIBFAM) +/* libfam monitoring interface */ + +static FAMConnection famc; + +static int +file_watch_init_fam(void) +{ + int n; + help_file *h; + FAMRequest famr; + const char *gamedir; + + memset(&famc, 0, sizeof famc); + + gamedir = getenv("GAMEDIR"); + if (!gamedir) { + do_rawlog(LT_TRACE, + "file_watch_init: Unable to get GAMEDIR environment variable."); + return -1; + } + + if (FAMOpen(&famc) < 0) { + do_rawlog(LT_TRACE, "file_watch_init: FAMOpen: %s", FamErrlist[FAMErrno]); + return -1; + } +#define WATCH(name) do { \ + const char *fullname = tprintf("%s/%s", gamedir, (name)); \ + do_rawlog(LT_TRACE, "Watching %s", fullname); \ + if (FAMMonitorFile(&famc, fullname, &famr, NULL) < 0) \ + do_rawlog(LT_TRACE, "file_watch_init:FAMMonitorFile(\"%s\"): %s", \ + (name), FamErrlist[FAMErrno]); \ + } while (0) + + do_rawlog(LT_TRACE, + "'No such file or directory' errors immediately following are probably harmless."); + for (n = 0; n < 2; n++) { + WATCH(options.connect_file[n]); + WATCH(options.motd_file[n]); + WATCH(options.wizmotd_file[n]); + WATCH(options.register_file[n]); + WATCH(options.quit_file[n]); + WATCH(options.down_file[n]); + WATCH(options.full_file[n]); + WATCH(options.guest_file[n]); + } + + for (h = hash_firstentry(&help_files); h; h = hash_nextentry(&help_files)) + WATCH(h->file); + +#undef WATCH + + return FAMCONNECTION_GETFD(&famc); +} + +static void +file_watch_event_fam(void) +{ + do_rawlog(LT_TRACE, "In file_watch_event_fam()"); + + while (FAMPending(&famc)) { + FAMEvent famev; + + memset(&famev, 0, sizeof famev); + + if (FAMNextEvent(&famc, &famev) < 0) { + do_rawlog(LT_TRACE, "file_watch_event: FAMNextEvent: %s", + FamErrlist[FAMErrno]); + break; + } + + do_rawlog(LT_TRACE, "Code is: %d for %s", famev.code, famev.filename); + + switch (famev.code) { + case FAMChanged: + case FAMDeleted: + reload_files(); + break; + default: + break; + } + } +} + +#endif + +/** Start monitoring various useful files for changes. + * \return descriptor of the notification service, or -1 on error + */ +int +file_watch_init(void) +{ +#ifdef HAVE_INOTIFY + return file_watch_init_in(); +#elif defined(HAVE_LIBFAM) + return file_watch_init_fam(); +#else + return -1; +#endif +} + +/** Test for modified files and re-read them if indicated. + * \param fd the notification monitorh descriptor + */ +void +file_watch_event(int fd __attribute__ ((__unused__))) +{ +#ifdef HAVE_INOTIFY + file_watch_event_in(fd); +#elif defined(HAVE_LIBFAM) + file_watch_event_fam(); +#endif + return; +} diff --git a/src/bufferq.c b/src/bufferq.c index aaa029d..4ecf072 100644 --- a/src/bufferq.c +++ b/src/bufferq.c @@ -10,9 +10,6 @@ #include "config.h" #include -#ifdef I_STDLIB -#include -#endif #ifdef I_UNISTD #include #endif @@ -22,8 +19,12 @@ #include #ifdef I_SYS_TIME #include +#ifdef TIME_WITH_SYS_TIME +#include #endif +#else #include +#endif #ifdef I_SYS_TYPES #include #endif @@ -37,7 +38,9 @@ #include "log.h" #include "confmagic.h" -static void shift_bufferq(BUFFERQ * bq, int space_needed); +#define BUFFERQLINEOVERHEAD (2*sizeof(int)+sizeof(time_t)+sizeof(dbref)) + +static void shift_bufferq(BUFFERQ *bq, int space_needed); /** Add data to a buffer queue. * \param bq pointer to buffer queue. @@ -46,7 +49,7 @@ static void shift_bufferq(BUFFERQ * bq, int space_needed); * \param msg caller-specific string to add. */ void -add_to_bufferq(BUFFERQ * bq, int type, dbref player, const char *msg) +add_to_bufferq(BUFFERQ *bq, int type, dbref player, const char *msg) { int len = strlen(msg); int room = len + 1 + BUFFERQLINEOVERHEAD; @@ -74,7 +77,7 @@ add_to_bufferq(BUFFERQ * bq, int type, dbref player, const char *msg) static void -shift_bufferq(BUFFERQ * bq, int space_needed) +shift_bufferq(BUFFERQ *bq, int space_needed) { char *p = bq->buffer; int size, jump; @@ -110,7 +113,6 @@ shift_bufferq(BUFFERQ * bq, int space_needed) } /** Allocate memory for a buffer queue to hold a given number of lines. - * \param bq pointer to buffer queue. * \param lines lines to allocate for buffer queue. * \retval address of allocated buffer queue. */ @@ -134,7 +136,7 @@ allocate_bufferq(int lines) * \param bq pointer to buffer queue. */ void -free_bufferq(BUFFERQ * bq) +free_bufferq(BUFFERQ *bq) { if (!bq) return; @@ -149,7 +151,7 @@ free_bufferq(BUFFERQ * bq) * \retval address of reallocated buffer queue. */ BUFFERQ * -reallocate_bufferq(BUFFERQ * bq, int lines) +reallocate_bufferq(BUFFERQ *bq, int lines) { char *newbuff; ptrdiff_t bufflen; @@ -167,7 +169,7 @@ reallocate_bufferq(BUFFERQ * bq, int lines) shift_bufferq(bq, bq->buffer_end - bq->buffer - bytes); } bufflen = bq->buffer_end - bq->buffer; - newbuff = (char *) realloc(bq->buffer, bytes); + newbuff = realloc(bq->buffer, bytes); if (newbuff) { bq->buffer = newbuff; bq->buffer_end = bq->buffer + bufflen; @@ -193,7 +195,7 @@ reallocate_bufferq(BUFFERQ * bq, int lines) * \return next message text or NULL if no more. */ char * -iter_bufferq(BUFFERQ * bq, char **p, dbref *player, int *type, +iter_bufferq(BUFFERQ *bq, char **p, dbref *player, int *type, time_t * timestamp) { static char tbuf1[BUFFER_LEN]; @@ -221,12 +223,12 @@ iter_bufferq(BUFFERQ * bq, char **p, dbref *player, int *type, return tbuf1; } -/** Size of bufferq buffer in lines. +/** Size of bufferq buffer in blocks. * \param bq pointer to buffer queue. - * \return size of buffer queue in lines + * \return size of buffer queue in 8k blocks */ int -bufferq_lines(BUFFERQ * bq) +bufferq_blocks(BUFFERQ *bq) { if (bq && bq->buffer) return bq->buffer_size / (BUFFER_LEN + BUFFERQLINEOVERHEAD); @@ -234,13 +236,36 @@ bufferq_lines(BUFFERQ * bq) return 0; } +/** Number of lines stored in queue. + * \param bq pointer to buffer queue. + * \return line count + */ +int +bufferq_lines(BUFFERQ *bq) +{ + int lines = 0; + char *p = NULL; + dbref player; + int type; + time_t t; + + + if (isempty_bufferq(bq)) + return 0; + + while (iter_bufferq(bq, &p, &player, &type, &t)) + lines++; + + return lines; +} + /** Is a buffer queue empty? * \param bq pointer to buffer queue. * \retval 1 the buffer queue is empty (has no messages). * \retval 0 the buffer queue is not empty (has messages). */ -int -isempty_bufferq(BUFFERQ * bq) +bool +isempty_bufferq(BUFFERQ *bq) { if (!bq || !bq->buffer) return 1; diff --git a/src/chunk.c b/src/chunk.c index d04c64f..a53a229 100644 --- a/src/chunk.c +++ b/src/chunk.c @@ -11,8 +11,8 @@ * on top of malloc(), with significantly reduced overhead and the ability * to rearrange allocations to actively control fragmentation and increase * locality. - * - * + * + * *

Basic operation:

* The managed memory pool is divided into regions of approximately 64KB. * These regions contain variable-size chunks representing allocated and @@ -22,14 +22,14 @@ * the used/free status, the size of the chunk, and the number of * dereferences for the chunk), and each region has additional overhead * of about 42 bytes. - * + * * Allocations are made with the chunk_create() call, which is given * the size of the data, the data value to be stored, and an initial * dereference count to be assigned to the chunk. Once created, the * value of a chunk cannot be changed; the storage is immutable. * chunk_create() returns an integral reference value that can be * used to retrieve or free the allocation. - * + * * Allocations are accessed with the chunk_fetch(), chunk_len(), and * chunk_derefs() calls. Each of these if given a reference (as * returned by chunk_create()), and chunk_fetch() is additionally @@ -37,10 +37,10 @@ * chunk_fetch() and chunk_len() increment a chunk's dereference * count (up to the maximum of 255), which is used in migration to * improve locality. - * + * * Allocations are freed with the chunk_delete() call, which also * requires a reference as input. - * + * * Finally, allocations are allowed to rearrange themselves with the * chunk_migration() call. chunk_migration() takes an array of * pointers to chunk references as input, and examines each of the @@ -53,8 +53,8 @@ * chunk_migration(); however, _all_ allocations made with chunk_create() * must eventually be submitted for migration in order to maintain the * memory pool in a non-fragmented state. - * - * + * + * *

Migration:

* Under normal conditions, extended use of this chunk allocation system * would lead to a significantly fragmented datastore, unless there was @@ -68,14 +68,14 @@ * incrementally, giving permission to move a small number of chunks * at any one time, and spreading out the cost of defragmenting the * data store. - * + * * Just because you give permission to move a chunk doesn't mean that it * will be moved. The chunk may be perfectly happy where it is, with * no need to move it elsewhere. Chunks are only moved when their * personal happiness would be improved by a move. In general, maximizing * the happiness of individual chunks will improve the happiness of the * whole. - * + * * There are two things that factor into a chunk's happiness. * The things that make a chunk unhappy are: *
    @@ -87,7 +87,7 @@ * Neither of these factors are absolute; both of them have different * weights that add into a general unhappiness for the chunk. The lower * the unhappiness, the better. - * + * * Over time and usage, the dereference counts for chunks will increase * and eventually reach a maximum value of 255. (The count is limited * by the fact that it's stored in a single byte for each chunk.) If @@ -102,8 +102,8 @@ * up incrementing the dereference count on all chunks, and thus all * regions). Given a dump frequency of once per hour (the default), there * should be a period change about every 2.6 days. - * - * + * + * *

    Statistics:

    * The chunk memory management system keeps several statistics about * the allocation pool, both to maintain good operation through active @@ -111,7 +111,7 @@ * using the system (and its designer ;-)). These statistics are * reported (in PennMUSH) through the use of the @stats command, * with /chunks switch. - * + * * @stats/chunks generates output similar to this: * \verbatim * Chunks: 99407 allocated ( 8372875 bytes, 223808 ( 2%) overhead) @@ -122,7 +122,7 @@ * Regions: 147 total, 16 cached * Paging: 158686 out, 158554 in * Storage: 9628500 total (86% saturation) - * + * * Period: 1 ( 5791834 accesses so far, 1085 chunks at max) * Migration: 245543 moves this period * 145536 slide @@ -139,16 +139,16 @@ * is the number of free chunks, their total size, and the amount of * fragmented free space (free space not in the largest free chunk for * its region is considered fragmented). - * + * * Next comes statistics on regions: the number of regions in use * and the number held in the memory cache. All regions not in the * cache are paged out to disk. Paging statistics follow, listing - * the number of times a region has been moved out of or into + * the number of times a region has been moved out of or into * memory cache. After that, the total amount of storage (in memory * or on disk) used is given, along with the saturation rate (where * saturation is indicated by what fraction of the used space is * actually allocated in chunks). - * + * * Finally comes statistics on migration and the migration period. * The period number is listed, along with the total number of * dereferences in the period and how many chunks have the maximum @@ -160,14 +160,14 @@ * are when an allocation is moved in order to fill in a free space; * the space can be either exactly filled by the move, or inexactly * filled (leaving some remaining free space). - * - * + * + * *

    Histograms:

    * The chunk memory management system can also display a few * histograms about itself. These histograms are reported (in PennMUSH) * through the use of the @stats command, with the /regions, /freespace, * or /paging switches. - * + * * All of @stats/regions, @stats/freespace, and @stas/paging produce * histograms vs. region average dereference count. The histograms * use buckets four counts wide, so all regions from 0-3 will be in @@ -176,7 +176,7 @@ * different, then the highest spikes will be allowed to extend off * the top of the histogram (with their real values labeled in * parenthesis next to them). - * + * * @stats/regions is a histogram of how many regions at each count * currently exist. In a healthy game, there should be a large spike * at some dereference count between 64 and 128 (representing the @@ -187,11 +187,11 @@ * areas (above the large spike). New migration periods occur when * the large spike would pass 128, at which point everything is halved * and the spike is pushed back down to 64. - * + * * @stats/freespace is a histogram of how much free space exists in * regions at each dereference count. This histogram is included * to aid in diagnosis of the cause for dropping saturation rates. - * + * * @stats/paging is a histogram of the number of regions being paged * in or out at each dereference count. As of this writing, a very * unhealthy behaviour is observed, wherein the histogram shows a @@ -219,8 +219,11 @@ #include #include #ifdef WIN32 +#include #include #else +#define _XOPEN_SOURCE 500 +#define __USE_UNIX98 #include #endif #include @@ -528,8 +531,8 @@ static int ignore; /**< Used to shut up compiler warnings when not assertin * the rest of the 64K bytes of the region contain chunks. */ typedef struct region_header { - u_int_16 region_id; /**< will be INVALID_REGION_ID if not in use */ - u_int_16 first_free; /**< offset of 1st free chunk */ + uint16_t region_id; /**< will be INVALID_REGION_ID if not in use */ + uint16_t first_free; /**< offset of 1st free chunk */ struct region_header *prev; /**< linked list prev for LRU cache */ struct region_header *next; /**< linked list next for LRU cache */ } RegionHeader; @@ -538,16 +541,16 @@ typedef struct region_header { /** In-memory (never paged) region info. */ typedef struct region { - u_int_16 used_count; /**< number of used chunks */ - u_int_16 free_count; /**< number of free chunks */ - u_int_16 free_bytes; /**< number of free bytes (with headers) */ - u_int_16 largest_free_chunk; /**< largest single free chunk */ - unsigned int total_derefs; /**< total of all used chunk derefs */ - unsigned int period_last_touched; /**< "this" period, for deref counts; + uint16_t used_count; /**< number of used chunks */ + uint16_t free_count; /**< number of free chunks */ + uint16_t free_bytes; /**< number of free bytes (with headers) */ + uint16_t largest_free_chunk; /**< largest single free chunk */ + uint32_t total_derefs; /**< total of all used chunk derefs */ + uint32_t period_last_touched; /**< "this" period, for deref counts; we don't page in regions to update counts on period change! */ RegionHeader *in_memory; /**< cache entry; NULL if paged out */ - u_int_16 oddballs[NUM_ODDBALLS]; /**< chunk offsets with odd derefs */ + uint16_t oddballs[NUM_ODDBALLS]; /**< chunk offsets with odd derefs */ } Region; #define RegionDerefs(region) \ @@ -580,19 +583,19 @@ static char child_filename[300]; /** Deref scale control. * When the deref counts get too big, the current period is incremented * and all derefs are divided by 2. */ -static u_int_32 curr_period; +static uint32_t curr_period; /* * Info about all regions */ -static u_int_32 region_count; /**< regions in use */ -static u_int_32 region_array_len; /**< length of regions array */ +static uint32_t region_count; /**< regions in use */ +static uint32_t region_array_len; /**< length of regions array */ static Region *regions; /**< regions array, realloced as (rarely) needed */ /* * regions presently in memory */ -static u_int_32 cached_region_count; /**< number of regions in cache */ +static uint32_t cached_region_count; /**< number of regions in cache */ static RegionHeader *cache_head; /**< most recently used region */ static RegionHeader *cache_tail; /**< least recently used region */ @@ -635,7 +638,7 @@ static int noisy_log = 0; /* * Forward decls */ -static void find_oddballs(u_int_16 region); +static void find_oddballs(uint16_t region); /* * Debug routines @@ -685,7 +688,7 @@ dump_debug_log(FILE * fp) /** Test if a chunk is migratable. */ static int -migratable(u_int_16 region, u_int_16 offset) +migratable(uint16_t region, uint16_t offset) { chunk_reference_t ref = ChunkReference(region, offset); int j; @@ -704,11 +707,11 @@ migratable(u_int_16 region, u_int_16 offset) * \param fp the FILE* to output to. */ static void -debug_dump_region(u_int_16 region, FILE * fp) +debug_dump_region(uint16_t region, FILE * fp) { Region *rp = regions + region; RegionHeader *rhp; - u_int_16 offset, count; + uint16_t offset, count; ASSERT(region < region_count); rhp = rp->in_memory; @@ -757,9 +760,9 @@ debug_dump_region(u_int_16 region, FILE * fp) * \param offset the offset to verify. */ static void -verify_used_chunk(u_int_16 region, u_int_16 offset) +verify_used_chunk(uint16_t region, uint16_t offset) { - u_int_16 pos; + uint16_t pos; ASSERT(region < region_count); @@ -782,7 +785,7 @@ verify_used_chunk(u_int_16 region, u_int_16 offset) * \return true if the region is valid. */ static int -region_is_valid(u_int_16 region) +region_is_valid(uint16_t region) { int result; Region *rp; @@ -795,8 +798,8 @@ region_is_valid(u_int_16 region) int len; int was_free; int dump; - u_int_16 next_free; - u_int_16 offset; + uint16_t next_free; + uint16_t offset; if (region >= region_count) { do_rawlog(LT_ERR, "region 0x%04x is not valid: region_count is 0x%04x", @@ -954,9 +957,8 @@ region_is_valid(u_int_16 region) * \param derefs the deref count to set on the chunk. */ static void -write_used_chunk(u_int_16 region, u_int_16 offset, u_int_16 full_len, - unsigned char const *data, u_int_16 data_len, - unsigned char derefs) +write_used_chunk(uint16_t region, uint16_t offset, uint16_t full_len, + unsigned char const *data, uint16_t data_len, uint8_t derefs) { unsigned char *cptr = ChunkPointer(region, offset); if (full_len <= MAX_SHORT_CHUNK_LEN + CHUNK_SHORT_DATA_OFFSET) { @@ -967,14 +969,14 @@ write_used_chunk(u_int_16 region, u_int_16 offset, u_int_16 full_len, memcpy(cptr + CHUNK_SHORT_DATA_OFFSET, data, data_len); } else if (full_len <= MAX_MEDIUM_CHUNK_LEN + CHUNK_MEDIUM_DATA_OFFSET) { /* chunk is medium */ - u_int_16 len = full_len - CHUNK_MEDIUM_DATA_OFFSET; + uint16_t len = full_len - CHUNK_MEDIUM_DATA_OFFSET; cptr[0] = (len >> 8) + CHUNK_USED + CHUNK_TAG1_MEDIUM + CHUNK_TAG2_MEDIUM; cptr[CHUNK_DEREF_OFFSET] = derefs; cptr[CHUNK_MEDIUM_LEN_LSB_OFFSET] = len & 0xff; memcpy(cptr + CHUNK_MEDIUM_DATA_OFFSET, data, data_len); } else { /* chunk is long */ - u_int_16 len = full_len - CHUNK_LONG_DATA_OFFSET; + uint16_t len = full_len - CHUNK_LONG_DATA_OFFSET; cptr[0] = CHUNK_USED + CHUNK_TAG1_LONG + CHUNK_TAG2_LONG; cptr[CHUNK_DEREF_OFFSET] = derefs; cptr[CHUNK_LONG_LEN_MSB_OFFSET] = len >> 8; @@ -990,8 +992,8 @@ write_used_chunk(u_int_16 region, u_int_16 offset, u_int_16 full_len, * \param next the offset for the next free chunk. */ static void -write_free_chunk(u_int_16 region, u_int_16 offset, u_int_16 full_len, - u_int_16 next) +write_free_chunk(uint16_t region, uint16_t offset, uint16_t full_len, + uint16_t next) { unsigned char *cptr = ChunkPointer(region, offset); if (full_len <= MAX_SHORT_CHUNK_LEN + CHUNK_SHORT_DATA_OFFSET) { @@ -1002,14 +1004,14 @@ write_free_chunk(u_int_16 region, u_int_16 offset, u_int_16 full_len, cptr[CHUNK_DEREF_OFFSET] = next & 0xff; } else if (full_len <= MAX_MEDIUM_CHUNK_LEN + CHUNK_MEDIUM_DATA_OFFSET) { /* chunk is medium */ - u_int_16 len = full_len - CHUNK_MEDIUM_DATA_OFFSET; + uint16_t len = full_len - CHUNK_MEDIUM_DATA_OFFSET; cptr[0] = (len >> 8) + CHUNK_FREE + CHUNK_TAG1_MEDIUM + CHUNK_TAG2_MEDIUM; cptr[CHUNK_MEDIUM_LEN_LSB_OFFSET] = len & 0xff; cptr[CHUNK_MEDIUM_DATA_OFFSET] = next >> 8; cptr[CHUNK_DEREF_OFFSET] = next & 0xff; } else { /* chunk is long */ - u_int_16 len = full_len - CHUNK_LONG_DATA_OFFSET; + uint16_t len = full_len - CHUNK_LONG_DATA_OFFSET; cptr[0] = CHUNK_FREE + CHUNK_TAG1_LONG + CHUNK_TAG2_LONG; cptr[CHUNK_LONG_LEN_MSB_OFFSET] = len >> 8; cptr[CHUNK_LONG_LEN_LSB_OFFSET] = len & 0xff; @@ -1024,7 +1026,7 @@ write_free_chunk(u_int_16 region, u_int_16 offset, u_int_16 full_len, * \param next the offset for the next free chunk. */ static void -write_next_free(u_int_16 region, u_int_16 offset, u_int_16 next) +write_next_free(uint16_t region, uint16_t offset, uint16_t next) { unsigned char *cptr = ChunkPointer(region, offset); if (ChunkIsShort(region, offset)) { @@ -1048,10 +1050,10 @@ write_next_free(u_int_16 region, u_int_16 offset, u_int_16 next) * \param offset the offset of the left-hand chunk to coalesce. */ static void -coalesce_frees(u_int_16 region, u_int_16 offset) +coalesce_frees(uint16_t region, uint16_t offset) { Region *rp = regions + region; - u_int_16 full_len, next; + uint16_t full_len, next; full_len = ChunkFullLen(region, offset); next = ChunkNextFree(region, offset); if (offset + full_len == next) { @@ -1069,10 +1071,10 @@ coalesce_frees(u_int_16 region, u_int_16 offset) * \param offset the offset of the chunk to free. */ static void -free_chunk(u_int_16 region, u_int_16 offset) +free_chunk(uint16_t region, uint16_t offset) { Region *rp = regions + region; - u_int_16 full_len, left; + uint16_t full_len, left; full_len = ChunkFullLen(region, offset); rp->total_derefs -= ChunkDerefs(region, offset); @@ -1106,7 +1108,7 @@ free_chunk(u_int_16 region, u_int_16 offset) rp->in_memory->first_free = offset; left = 0; } else { - u_int_16 next; + uint16_t next; next = ChunkNextFree(region, left); while (next && next < offset) { left = next; @@ -1124,11 +1126,11 @@ free_chunk(u_int_16 region, u_int_16 offset) * \param region the region to search for a large hole in. * \return the size of the largest free chunk. */ -static u_int_16 -largest_hole(u_int_16 region) +static uint16_t +largest_hole(uint16_t region) { - u_int_16 size; - u_int_16 offset; + uint16_t size; + uint16_t offset; size = 0; for (offset = regions[region].in_memory->first_free; offset; offset = ChunkNextFree(region, offset)) @@ -1147,11 +1149,11 @@ largest_hole(u_int_16 region) * \param align the alignment to use: 0 = easiest, 1 = left, 2 = right. * \return the offset of the allocated space. */ -static u_int_16 -split_hole(u_int_16 region, u_int_16 offset, u_int_16 full_len, int align) +static uint16_t +split_hole(uint16_t region, uint16_t offset, uint16_t full_len, int align) { Region *rp = regions + region; - u_int_16 hole_len = ChunkFullLen(region, offset); + uint16_t hole_len = ChunkFullLen(region, offset); rp->used_count++; if (full_len <= MAX_SHORT_CHUNK_LEN + CHUNK_SHORT_DATA_OFFSET) { @@ -1174,7 +1176,7 @@ split_hole(u_int_16 region, u_int_16 offset, u_int_16 full_len, int align) if (rp->in_memory->first_free == offset) rp->in_memory->first_free = ChunkNextFree(region, offset); else { - u_int_16 hole; + uint16_t hole; for (hole = rp->in_memory->first_free; hole; hole = ChunkNextFree(region, hole)) if (ChunkNextFree(region, hole) == offset) @@ -1201,7 +1203,7 @@ split_hole(u_int_16 region, u_int_16 offset, u_int_16 full_len, int align) if (rp->in_memory->first_free == offset) rp->in_memory->first_free += full_len; else { - u_int_16 hole; + uint16_t hole; for (hole = rp->in_memory->first_free; hole; hole = ChunkNextFree(region, hole)) if (ChunkNextFree(region, hole) == offset) @@ -1232,16 +1234,17 @@ split_hole(u_int_16 region, u_int_16 offset, u_int_16 full_len, int align) * \param region region to read */ static void -read_cache_region(fd_type fd, RegionHeader * rhp, u_int_16 region) +read_cache_region(fd_type fd, RegionHeader *rhp, uint16_t region) { off_t file_offset = region * REGION_SIZE; int j; char *pos; size_t remaining; - int done; + ssize_t done; debug_log("read_cache_region %04x", region); +#ifndef HAVE_PREAD /* Try to seek up to 3 times... */ for (j = 0; j < 3; j++) #ifdef WIN32 @@ -1257,28 +1260,26 @@ read_cache_region(fd_type fd, RegionHeader * rhp, u_int_16 region) #else mush_panicf("chunk swap file seek, errno %d: %s", errno, strerror(errno)); #endif +#endif /* !HAVE_PREAD */ pos = (char *) rhp; remaining = REGION_SIZE; for (j = 0; j < 10; j++) { -#ifdef WIN32 -#ifndef __MINGW32__ +#if defined(HAVE_PREAD) + done = pread(fd, pos, remaining, file_offset); +#elif defined(WIN32) && !defined(__MINGW32__) if (!ReadFile(fd, pos, remaining, &done, NULL)) { /* nothing */ } -#endif #else done = read(fd, pos, remaining); #endif if (done >= 0) { remaining -= done; pos += done; + file_offset += done; if (!remaining) return; } -#ifndef WIN32 - if (done == -1 && errno == EAGAIN) - sleep(0); -#endif } #ifdef WIN32 mush_panicf("chunk swap file read, %d remaining, GetLastError %d", @@ -1295,16 +1296,17 @@ read_cache_region(fd_type fd, RegionHeader * rhp, u_int_16 region) * \param region region to write */ static void -write_cache_region(fd_type fd, RegionHeader * rhp, u_int_16 region) +write_cache_region(fd_type fd, RegionHeader *rhp, uint16_t region) { off_t file_offset = region * REGION_SIZE; int j; char *pos; size_t remaining; - int done; + ssize_t done; debug_log("write_cache_region %04x", region); +#ifndef HAVE_PWRITE /* Try to seek up to 3 times... */ for (j = 0; j < 3; j++) #ifdef WIN32 @@ -1320,30 +1322,32 @@ write_cache_region(fd_type fd, RegionHeader * rhp, u_int_16 region) #else mush_panicf("chunk swap file seek, errno %d: %s", errno, strerror(errno)); #endif +#endif /* !HAVE_PWRITE */ pos = (char *) rhp; remaining = REGION_SIZE; + + /* SW: I'm not sure why Talek has this loop so many times -- the + only recoverable way the writes should fail is if they're + interrupted by a signal and can't be restarted for some + reason. */ for (j = 0; j < 10; j++) { -#ifdef WIN32 -#ifndef __MINGW32__ + +#if defined(HAVE_PWRITE) + done = pwrite(fd, pos, remaining, file_offset); +#elif defined(WIN32) && !defined(__MINGW32__) if (!WriteFile(fd, pos, remaining, &done, NULL)) { /* nothing */ } -#else - done = write(fd, pos, remaining); -#endif #else done = write(fd, pos, remaining); #endif if (done >= 0) { remaining -= done; pos += done; + file_offset += done; if (!remaining) return; } -#ifndef WIN32 - if (done == -1 && errno == EAGAIN) - sleep(0); -#endif } #ifdef WIN32 mush_panicf("chunk swap file write, %d remaining, GetLastError %d", @@ -1358,7 +1362,7 @@ write_cache_region(fd_type fd, RegionHeader * rhp, u_int_16 region) * \param rhp the cached region to keep around. */ static void -touch_cache_region(RegionHeader * rhp) +touch_cache_region(RegionHeader *rhp) { debug_log("touch_cache_region %04x", rhp->region_id); @@ -1435,11 +1439,11 @@ find_available_cache_region(void) * \param region the region to bring in. */ static void -bring_in_region(u_int_16 region) +bring_in_region(uint16_t region) { Region *rp = regions + region; RegionHeader *rhp, *prev, *next; - u_int_32 offset; + uint32_t offset; unsigned int shift; debug_log("bring_in_region %04x", region); @@ -1502,10 +1506,10 @@ bring_in_region(u_int_16 region) * Recycle an empty region if possible. * \return the region id for the new region. */ -static u_int_16 +static uint16_t create_region(void) { - u_int_16 region; + uint16_t region; for (region = 0; region < region_count; region++) if (regions[region].used_count == 0) @@ -1547,11 +1551,11 @@ create_region(void) * \param region the region to search in. */ static void -find_oddballs(u_int_16 region) +find_oddballs(uint16_t region) { Region *rp = regions + region; int j, d1, d2; - u_int_16 offset, len; + uint16_t offset, len; int mean; for (j = 0; j < NUM_ODDBALLS; j++) @@ -1595,10 +1599,10 @@ find_oddballs(u_int_16 region) * \param old_region the region the chunk was in before (if any). * \return the region id for the least unhappy region. */ -static u_int_16 -find_best_region(u_int_16 full_len, int derefs, u_int_16 old_region) +static uint16_t +find_best_region(uint16_t full_len, int derefs, uint16_t old_region) { - u_int_16 best_region, region; + uint16_t best_region, region; int best_score, score; int free_bytes; Region *rp; @@ -1653,11 +1657,11 @@ find_best_region(u_int_16 full_len, int derefs, u_int_16 old_region) * \param old_region the region the chunk was in before (if any). * \param old_offset the offset the chunk was at before (if any). */ -static u_int_16 -find_best_offset(u_int_16 full_len, u_int_16 region, - u_int_16 old_region, u_int_16 old_offset) +static uint16_t +find_best_offset(uint16_t full_len, uint16_t region, + uint16_t old_region, uint16_t old_offset) { - u_int_16 fits, offset; + uint16_t fits, offset; bring_in_region(region); @@ -1740,7 +1744,7 @@ chunk_statistics(dbref player) int free_large = 0; int used_count = 0; int used_bytes = 0; - u_int_16 rid; + uint16_t rid; for (rid = 0; rid < region_count; rid++) { free_count += regions[rid].free_count; @@ -1819,7 +1823,7 @@ chunk_page_stats(dbref player) static void chunk_region_statistics(dbref player) { - u_int_16 rid; + uint16_t rid; const char *s; if (!GoodObject(player)) { @@ -1951,10 +1955,10 @@ migrate_sort(void) * \param which the index (in the migration arrays) of the chunk to move. */ static void -migrate_slide(u_int_16 region, u_int_16 offset, int which) +migrate_slide(uint16_t region, uint16_t offset, int which) { Region *rp = regions + region; - u_int_16 o_len, len, next, other, prev, o_off, o_oth; + uint16_t o_len, len, next, other, prev, o_off, o_oth; debug_log("migrate_slide %d (%08x) to %04x%04x", which, m_references[which][0], region, offset); @@ -2019,10 +2023,10 @@ migrate_slide(u_int_16 region, u_int_16 offset, int which) * \param which the index (in the migration arrays) of the chunk to move. */ static void -migrate_move(u_int_16 region, u_int_16 offset, int which, int align) +migrate_move(uint16_t region, uint16_t offset, int which, int align) { Region *rp = regions + region; - u_int_16 s_reg, s_off, s_len, o_off, length; + uint16_t s_reg, s_off, s_len, o_off, length; Region *srp; debug_log("migrate_move %d (%08x) to %04x%04x, alignment %d", @@ -2081,11 +2085,11 @@ migrate_move(u_int_16 region, u_int_16 offset, int which, int align) } static void -migrate_region(u_int_16 region) +migrate_region(uint16_t region) { chunk_reference_t high, low; int j, derefs; - u_int_16 offset, length, best_region, best_offset; + uint16_t offset, length, best_region, best_offset; bring_in_region(region); @@ -2120,9 +2124,9 @@ migrate_region(u_int_16 region) * \return the chunk reference for retrieving (or deleting) the data. */ chunk_reference_t -chunk_create(unsigned char const *data, u_int_16 len, unsigned char derefs) +chunk_create(unsigned char const *data, uint16_t len, uint8_t derefs) { - u_int_16 full_len, region, offset; + uint16_t full_len, region, offset; if (len < MIN_CHUNK_LEN || len > MAX_CHUNK_LEN) mush_panicf("Illegal chunk length requested: %d bytes", len); @@ -2155,7 +2159,7 @@ chunk_create(unsigned char const *data, u_int_16 len, unsigned char derefs) void chunk_delete(chunk_reference_t reference) { - u_int_16 region, offset; + uint16_t region, offset; region = ChunkReferenceToRegion(reference); offset = ChunkReferenceToOffset(reference); ASSERT(region < region_count); @@ -2182,11 +2186,11 @@ chunk_delete(chunk_reference_t reference) * \param buffer_len the length of the buffer. * \return the length of the data. */ -u_int_16 +uint16_t chunk_fetch(chunk_reference_t reference, - unsigned char *buffer, u_int_16 buffer_len) + unsigned char *buffer, uint16_t buffer_len) { - u_int_16 region, offset, len; + uint16_t region, offset, len; region = ChunkReferenceToRegion(reference); offset = ChunkReferenceToOffset(reference); ASSERT(region < region_count); @@ -2215,7 +2219,7 @@ chunk_fetch(chunk_reference_t reference, * \param reference the reference to the chunk to be queried. * \return the length of the data. */ -u_int_16 +uint16_t chunk_len(chunk_reference_t reference) { return chunk_fetch(reference, NULL, 0); @@ -2230,7 +2234,7 @@ chunk_len(chunk_reference_t reference) unsigned char chunk_derefs(chunk_reference_t reference) { - u_int_16 region, offset; + uint16_t region, offset; region = ChunkReferenceToRegion(reference); offset = ChunkReferenceToOffset(reference); ASSERT(region < region_count); @@ -2242,17 +2246,17 @@ chunk_derefs(chunk_reference_t reference) } /** Migrate allocated chunks around. - * + * * \param count the number of chunks to move. * \param references an array of pointers to chunk references, * which will be updated in place if necessary. */ void -chunk_migration(int count, chunk_reference_t ** references) +chunk_migration(int count, chunk_reference_t **references) { int k, l; unsigned total; - u_int_16 region, offset; + uint16_t region, offset; debug_log("*** chunk_migration starts, count = %d", count); @@ -2317,7 +2321,7 @@ int chunk_num_swapped(void) { int count; - u_int_16 region; + uint16_t region; count = 0; for (region = 0; region < region_count; region++) if (!regions[region].in_memory) @@ -2355,7 +2359,7 @@ chunk_init(void) #ifdef DEBUG_CHUNK_MALLOC do_rawlog(LT_TRACE, "CHUNK: malloc()ing initial region array"); #endif - regions = mush_malloc(region_array_len * sizeof(Region), "chunk region list"); + regions = mush_calloc(region_array_len, sizeof(Region), "chunk region list"); if (!regions) mush_panic("cannot malloc space for chunk region list"); @@ -2409,7 +2413,7 @@ chunk_new_period(void) { RegionHeader *rhp; Region *rp; - u_int_16 region, offset; + uint16_t region, offset; int shift; #ifdef LOG_CHUNK_STATS diff --git a/src/cmds.c b/src/cmds.c index b65f6a2..fd051ab 100644 --- a/src/cmds.c +++ b/src/cmds.c @@ -22,7 +22,6 @@ #include "attrib.h" #include "extmail.h" #include "malias.h" -#include "getpgsiz.h" #include "parse.h" #include "access.h" #include "version.h" @@ -47,7 +46,7 @@ void do_list(dbref player, char *arg, int lc); void do_writelog(dbref player, char *str, int ltype); void do_readcache(dbref player); void do_scan(dbref player, char *command, int flag); -void do_uptime(dbref player, int mortal); +void do_uptime(dbref player); extern int config_set(const char *opt, char *val, int source, int restrictions); /** Is there a right-hand side of the equal sign? From command.c */ @@ -95,11 +94,13 @@ COMMAND (cmd_attribute) { do_attribute_info(player, arg_left); } -COMMAND (cmd_atrchown) { +COMMAND(cmd_atrchown) +{ do_atrchown(player, arg_left, arg_right); } -COMMAND (cmd_boot) { +COMMAND(cmd_boot) +{ if (SW_ISSET(sw, SWITCH_PORT)) do_boot(player, arg_left, BOOT_DESC); else if (SW_ISSET(sw, SWITCH_ME)) @@ -110,7 +111,8 @@ COMMAND (cmd_boot) { /** Has the break command been called? */ -COMMAND (cmd_break) { +COMMAND(cmd_break) +{ if (parse_boolean(arg_left)) { global_eval_context.break_called = 1; if (arg_right && *arg_right) { @@ -124,7 +126,8 @@ COMMAND (cmd_break) { } } -COMMAND (cmd_assert) { +COMMAND(cmd_assert) +{ if (!parse_boolean(arg_left)) { global_eval_context.break_called = 1; if (arg_right && *arg_right) { @@ -139,23 +142,28 @@ COMMAND (cmd_assert) { } -COMMAND (cmd_chownall) { +COMMAND(cmd_chownall) +{ do_chownall(player, arg_left, arg_right, SW_ISSET(sw, SWITCH_PRESERVE)); } -COMMAND (cmd_chown) { +COMMAND(cmd_chown) +{ do_chown(player, arg_left, arg_right, SW_ISSET(sw, SWITCH_PRESERVE)); } -COMMAND (cmd_chzoneall) { +COMMAND(cmd_chzoneall) +{ do_chzoneall(player, arg_left, arg_right); } -COMMAND (cmd_chzone) { +COMMAND(cmd_chzone) +{ (void) do_chzone(player, arg_left, arg_right, 1); } -COMMAND (cmd_config) { +COMMAND(cmd_config) +{ int lc; lc = SW_ISSET(sw, SWITCH_LOWERCASE); if (SW_ISSET(sw, SWITCH_GLOBALS)) @@ -194,26 +202,31 @@ COMMAND (cmd_config) { do_config_list(player, arg_left, lc); } -COMMAND (cmd_cpattr) { +COMMAND(cmd_cpattr) +{ do_cpattr(player, arg_left, args_right, 0, SW_ISSET(sw, SWITCH_NOFLAGCOPY)); } -COMMAND (cmd_create) { +COMMAND(cmd_create) +{ do_create(player, arg_left, parse_integer(arg_right)); } -COMMAND (cmd_clone) { +COMMAND(cmd_clone) +{ if (SW_ISSET(sw, SWITCH_PRESERVE)) do_clone(player, arg_left, arg_right, SWITCH_PRESERVE); else do_clone(player, arg_left, arg_right, SWITCH_NONE); } -COMMAND (cmd_dbck) { +COMMAND(cmd_dbck) +{ do_dbck(player); } -COMMAND (cmd_decompile) { +COMMAND(cmd_decompile) +{ char prefix[BUFFER_LEN]; int sd = SW_ISSET(sw, SWITCH_SKIPDEFAULTS); *prefix = '\0'; @@ -315,7 +328,8 @@ COMMAND (cmd_dolist) { do_dolist(player, arg_left, arg_right, cause, flags); } -COMMAND (cmd_dump) { +COMMAND(cmd_dump) +{ if (SW_ISSET(sw, SWITCH_PARANOID)) do_dump(player, arg_left, DUMP_PARANOID); else if (SW_ISSET(sw, SWITCH_DEBUG)) @@ -324,17 +338,20 @@ COMMAND (cmd_dump) { do_dump(player, arg_left, DUMP_NORMAL); } -COMMAND (cmd_edit) { +COMMAND(cmd_edit) +{ do_gedit(player, arg_left, args_right, SW_ISSET(sw, SWITCH_FIRST) ? EDIT_FIRST : EDIT_ALL, SW_ISSET(sw, SWITCH_CHECK) ? 0 : 1); } -COMMAND (cmd_elock) { +COMMAND(cmd_elock) +{ do_lock(player, arg_left, arg_right, Enter_Lock); } -COMMAND (cmd_emit) { +COMMAND(cmd_emit) +{ int spflags = !strcmp(cmd->name, "@NSEMIT") ? PEMIT_SPOOF : 0; SPOOF(player, cause, sw); @@ -348,11 +365,13 @@ COMMAND (cmd_emit) { } } -COMMAND (cmd_enable) { +COMMAND(cmd_enable) +{ do_enable(player, arg_left, 1); } -COMMAND (cmd_entrances) { +COMMAND(cmd_entrances) +{ if (SW_ISSET(sw, SWITCH_EXITS)) do_entrances(player, arg_left, args_right, ENT_EXITS); else if (SW_ISSET(sw, SWITCH_THINGS)) @@ -365,19 +384,23 @@ COMMAND (cmd_entrances) { do_entrances(player, arg_left, args_right, ENT_ALL); } -COMMAND (cmd_eunlock) { +COMMAND(cmd_eunlock) +{ do_unlock(player, arg_left, Enter_Lock); } -COMMAND (cmd_find) { +COMMAND(cmd_find) +{ do_find(player, arg_left, args_right); } -COMMAND (cmd_firstexit) { +COMMAND(cmd_firstexit) +{ do_firstexit(player, arg_left); } -COMMAND (cmd_flag) { +COMMAND(cmd_flag) +{ if (SW_ISSET(sw, SWITCH_LIST)) do_list_flags(player, arg_left, 0); else if (SW_ISSET(sw, SWITCH_ADD)) @@ -400,11 +423,13 @@ COMMAND (cmd_flag) { do_flag_info("FLAG", player, arg_left); } -COMMAND (cmd_force) { +COMMAND(cmd_force) +{ do_force(player, arg_left, arg_right); } -COMMAND (cmd_function) { +COMMAND(cmd_function) +{ if (SW_ISSET(sw, SWITCH_DELETE)) do_function_delete(player, arg_left); else if (SW_ISSET(sw, SWITCH_ENABLE)) @@ -412,7 +437,8 @@ COMMAND (cmd_function) { else if (SW_ISSET(sw, SWITCH_DISABLE)) do_function_toggle(player, arg_left, 0); else if (SW_ISSET(sw, SWITCH_RESTRICT)) - do_function_restrict(player, arg_left, args_right[1]); + do_function_restrict(player, arg_left, args_right[1], + SW_ISSET(sw, SWITCH_BUILTIN)); else if (SW_ISSET(sw, SWITCH_RESTORE)) do_function_restore(player, arg_left); else { @@ -453,6 +479,8 @@ COMMAND (cmd_grep) { COMMAND (cmd_halt) { if (SW_ISSET(sw, SWITCH_ALL)) do_allhalt(player); + else if(SW_BY_NAME(sw, "PID")) + do_haltpid(player, arg_left); else do_halt1(player, arg_left, arg_right); } @@ -533,14 +561,16 @@ COMMAND (cmd_list) { do_list(player, arg_left, lc); } -COMMAND (cmd_lock) { +COMMAND(cmd_lock) +{ if ((switches) && (switches[0])) do_lock(player, arg_left, arg_right, switches); else do_lock(player, arg_left, arg_right, Basic_Lock); } -COMMAND (cmd_log) { +COMMAND(cmd_log) +{ if (SW_ISSET(sw, SWITCH_CHECK)) do_writelog(player, arg_left, LT_CHECK); else if (SW_ISSET(sw, SWITCH_CMD)) @@ -557,7 +587,8 @@ COMMAND (cmd_log) { do_writelog(player, arg_left, LT_CMD); } -COMMAND (cmd_logwipe) { +COMMAND(cmd_logwipe) +{ if (SW_ISSET(sw, SWITCH_CHECK)) do_logwipe(player, LT_CHECK, arg_left); else if (SW_ISSET(sw, SWITCH_CMD)) @@ -631,7 +662,8 @@ COMMAND (cmd_mail) { } -COMMAND (cmd_malias) { +COMMAND(cmd_malias) +{ if (SW_ISSET(sw, SWITCH_LIST)) do_malias_list(player); else if (SW_ISSET(sw, SWITCH_ALL)) @@ -667,14 +699,54 @@ COMMAND (cmd_malias) { } #endif -COMMAND (cmd_map) { +COMMAND(cmd_map) +{ unsigned int flags = DOL_MAP; if (SW_ISSET(sw, SWITCH_DELIMIT)) flags |= DOL_DELIM; do_dolist(player, arg_left, arg_right, cause, flags); } -COMMAND (cmd_motd) { +COMMAND(cmd_message) +{ + char *message; + char *attrib; + unsigned int flags = 0; + int numargs, i; + char *args[10]; + + if (!(SW_ISSET(sw, SWITCH_SPOOF) && (controls(player, cause) + || Can_Nspemit(player)))) { + cause = player; + } + + for (numargs = 1; args_right[numargs] && numargs < 13; numargs++) ; + + switch (numargs) { + case 1: + notify(player, T("@message them with what?")); + return; + case 2: + notify(player, T("Use what attribute for the @message?")); + return; + } + if (!*arg_left) { + notify(player, T("@message who?")); + return; + } + + message = args_right[1]; + attrib = args_right[2]; + + for (i = 0; (i + 3) < numargs; i++) { + args[i] = args_right[i + 3]; + } + + do_message_list(player, cause, arg_left, attrib, message, flags, i, args); +} + +COMMAND(cmd_motd) +{ if (SW_ISSET(sw, SWITCH_CONNECT)) do_motd(player, MOTD_MOTD, arg_left); else if (SW_ISSET(sw, SWITCH_LIST)) @@ -687,45 +759,55 @@ COMMAND (cmd_motd) { do_motd(player, MOTD_MOTD, arg_left); } -COMMAND (cmd_mvattr) { +COMMAND(cmd_mvattr) +{ do_cpattr(player, arg_left, args_right, 1, SW_ISSET(sw, SWITCH_NOFLAGCOPY)); } -COMMAND (cmd_name) { +COMMAND(cmd_name) +{ do_name(player, arg_left, arg_right); } -COMMAND (cmd_newpassword) { +COMMAND(cmd_newpassword) +{ do_newpassword(player, cause, arg_left, arg_right); } -COMMAND (cmd_nuke) { +COMMAND(cmd_nuke) +{ do_destroy(player, arg_left, 1); } -COMMAND (cmd_oemit) { +COMMAND(cmd_oemit) +{ int spflags = !strcmp(cmd->name, "@NSOEMIT") ? PEMIT_SPOOF : 0; SPOOF(player, cause, sw); do_oemit_list(player, arg_left, arg_right, spflags); } -COMMAND (cmd_open) { +COMMAND(cmd_open) +{ do_open(player, arg_left, args_right); } -COMMAND (cmd_parent) { +COMMAND(cmd_parent) +{ do_parent(player, arg_left, arg_right); } -COMMAND (cmd_password) { +COMMAND(cmd_password) +{ do_password(player, cause, arg_left, arg_right); } -COMMAND (cmd_pcreate) { +COMMAND(cmd_pcreate) +{ do_pcreate(player, arg_left, arg_right); } -COMMAND (cmd_pemit) { +COMMAND(cmd_pemit) +{ int flags; SPOOF(player, cause, sw); @@ -754,7 +836,8 @@ COMMAND (cmd_poor) { do_poor(player, arg_left); } -COMMAND (cmd_ps) { +COMMAND(cmd_ps) +{ if (SW_ISSET(sw, SWITCH_ALL)) do_queue(player, arg_left, QUEUE_ALL); else if (SW_ISSET(sw, SWITCH_SUMMARY) || SW_ISSET(sw, SWITCH_COUNT)) @@ -765,11 +848,13 @@ COMMAND (cmd_ps) { do_queue(player, arg_left, QUEUE_NORMAL); } -COMMAND (cmd_purge) { +COMMAND(cmd_purge) +{ do_purge(player); } -COMMAND (cmd_quota) { +COMMAND(cmd_quota) +{ if (SW_ISSET(sw, SWITCH_ALL)) do_allquota(player, arg_left, (SW_ISSET(sw, SWITCH_QUIET))); else if (SW_ISSET(sw, SWITCH_SET)) @@ -778,11 +863,13 @@ COMMAND (cmd_quota) { do_quota(player, arg_left, "", 0); } -COMMAND (cmd_readcache) { +COMMAND(cmd_readcache) +{ do_readcache(player); } -COMMAND (cmd_remit) { +COMMAND(cmd_remit) +{ int flags; SPOOF(player, cause, sw); if (SW_ISSET(sw, SWITCH_SILENT)) @@ -823,20 +910,24 @@ COMMAND (cmd_scan) { CHECK_SELF | CHECK_HERE | CHECK_ZONE | CHECK_GLOBAL); } -COMMAND (cmd_search) { +COMMAND(cmd_search) +{ do_search(player, arg_left, args_right); } -COMMAND (cmd_select) { +COMMAND(cmd_select) +{ do_switch(player, arg_left, args_right, cause, 1, SW_ISSET(sw, SWITCH_NOTIFY), SW_ISSET(sw, SWITCH_REGEXP)); } -COMMAND (cmd_set) { +COMMAND(cmd_set) +{ do_set(player, arg_left, arg_right); } -COMMAND (cmd_shutdown) { +COMMAND(cmd_shutdown) +{ enum shutdown_type paranoid; paranoid = (SW_ISSET(sw, SWITCH_PARANOID)) ? SHUT_PARANOID : SHUT_NORMAL ; if (SW_ISSET(sw, SWITCH_REBOOT)) @@ -847,7 +938,8 @@ COMMAND (cmd_shutdown) { do_shutdown(player, paranoid); } -COMMAND (cmd_sitelock) { +COMMAND(cmd_sitelock) +{ if (SW_ISSET(sw, SWITCH_BAN)) do_sitelock(player, arg_left, NULL, NULL, SITELOCK_BAN); else if (SW_ISSET(sw, SWITCH_REGISTER)) @@ -864,7 +956,8 @@ COMMAND (cmd_sitelock) { do_sitelock(player, arg_left, args_right[1], args_right[2], SITELOCK_ADD); } -COMMAND (cmd_stats) { +COMMAND(cmd_stats) +{ if (SW_ISSET(sw, SWITCH_TABLES)) do_list_memstats(player); else if (SW_ISSET(sw, SWITCH_CHUNKS)) { @@ -882,7 +975,8 @@ COMMAND (cmd_stats) { do_stats(player, arg_left); } -COMMAND (cmd_sweep) { +COMMAND(cmd_sweep) +{ if (SW_ISSET(sw, SWITCH_CONNECTED)) do_sweep(player, "connected"); else if (SW_ISSET(sw, SWITCH_HERE)) @@ -895,17 +989,20 @@ COMMAND (cmd_sweep) { do_sweep(player, arg_left); } -COMMAND (cmd_switch) { +COMMAND(cmd_switch) +{ do_switch(player, arg_left, args_right, cause, SW_ISSET(sw, SWITCH_FIRST), SW_ISSET(sw, SWITCH_NOTIFY), SW_ISSET(sw, SWITCH_REGEXP)); } -COMMAND (cmd_squota) { +COMMAND(cmd_squota) +{ do_quota(player, arg_left, arg_right, 1); } -COMMAND (cmd_teleport) { +COMMAND(cmd_teleport) +{ if (rhs_present && !*arg_right) notify(player, T("You can't teleport to nothing!")); else @@ -937,7 +1034,7 @@ COMMAND (cmd_unlock) { } COMMAND (cmd_uptime) { - do_uptime(player, SW_ISSET(sw, SWITCH_MORTAL)); + do_uptime(player); } COMMAND (cmd_uunlock) { @@ -1009,35 +1106,43 @@ COMMAND (cmd_examine) { do_examine(player, arg_left, EXAM_NORMAL, all); } -COMMAND (cmd_empty) { +COMMAND(cmd_empty) +{ do_empty(player, arg_left); } -COMMAND (cmd_enter) { +COMMAND(cmd_enter) +{ do_enter(player, arg_left); } -COMMAND (cmd_dismiss) { +COMMAND(cmd_dismiss) +{ do_dismiss(player, arg_left); } -COMMAND (cmd_desert) { +COMMAND(cmd_desert) +{ do_desert(player, arg_left); } -COMMAND (cmd_follow) { +COMMAND(cmd_follow) +{ do_follow(player, arg_left); } -COMMAND (cmd_unfollow) { +COMMAND(cmd_unfollow) +{ do_unfollow(player, arg_left); } -COMMAND (cmd_get) { +COMMAND(cmd_get) +{ do_get(player, arg_left); } -COMMAND (cmd_buy) { +COMMAND(cmd_buy) +{ char *from = NULL; char *forwhat = NULL; int price = -1; @@ -1145,15 +1250,17 @@ COMMAND (command_atrset) { do_set_atr(thing, switches, arg_right, player, 0x1 | (SW_ISSET(sw, SWITCH_NOEVAL) ? 0 : 0x02)); } else { - do_set_atr(thing, switches, NULL, player, 1); + do_set_atr(thing, switches, NULL, player, 0x1); } } -COMMAND (cmd_null) { +COMMAND(cmd_null) +{ return; } -COMMAND (cmd_warn_on_missing) { +COMMAND(cmd_warn_on_missing) +{ notify_format(Owner(player), T ("No command found in code by %s - don't start code with functions."), diff --git a/src/command.c b/src/command.c index fee00aa..4e6d98c 100644 --- a/src/command.c +++ b/src/command.c @@ -14,6 +14,8 @@ #include "config.h" #include +#include +#include #include "conf.h" #include "externs.h" @@ -23,17 +25,18 @@ #include "match.h" #include "attrib.h" #include "extmail.h" -#include "getpgsiz.h" #include "parse.h" #include "access.h" #include "version.h" #include "ptab.h" #include "htab.h" +#include "strtree.h" #include "function.h" #include "command.h" #include "mymalloc.h" #include "flags.h" #include "log.h" +#include "sort.h" #include "cmds.h" #include "confmagic.h" @@ -42,9 +45,11 @@ PTAB ptab_command_perms; /**< Prefix table for command permissions */ HASHTAB htab_reserved_aliases; /**< Hash table for reserved command aliases */ +slab *command_slab = NULL; /**< slab for command_info structs */ + static const char *command_isattr(char *command); static int command_check(dbref player, COMMAND_INFO *cmd, switch_mask sw); -static int switch_find(COMMAND_INFO *cmd, char *sw); +static int switch_find(COMMAND_INFO *cmd, const char *sw); static void strccat(char *buff, char **bp, const char *from); static int has_hook(struct hook_data *hook); extern int global_fun_invocations; /**< Counter for function invocations */ @@ -52,8 +57,21 @@ extern int global_fun_recursions; /**< Counter for function recursion */ int run_hook(dbref player, dbref cause, struct hook_data *hook, char *saveregs[], int save); +int run_hook_override(COMMAND_INFO *cmd, dbref player, const char *commandraw); int command_lock(const char *name, const char *lock); +SWITCH_VALUE *dyn_switch_list = NULL; +int switch_bytes = 0; +size_t num_switches = 0; + +enum command_load_state { CMD_LOAD_BUILTIN, + CMD_LOAD_LOCAL, + CMD_LOAD_DONE +}; +static enum command_load_state command_state = CMD_LOAD_BUILTIN; +static StrTree switch_names; + + /** The list of standard commands. Additional commands can be added * at runtime with add_command(). */ @@ -74,7 +92,7 @@ COMLIST commands[] = { {"@BOOT", "PORT ME", cmd_boot, CMD_T_ANY, NULL}, {"@BREAK", NULL, cmd_break, CMD_T_ANY | CMD_T_EQSPLIT | CMD_T_RS_NOPARSE, NULL}, #ifdef CHAT_SYSTEM - {"@CEMIT", "NOEVAL NOISY SPOOF", cmd_cemit, + {"@CEMIT", "NOEVAL NOISY SILENT SPOOF", cmd_cemit, CMD_T_ANY | CMD_T_EQSPLIT | CMD_T_NOGAGGED, NULL}, {"@CHANNEL", "LIST ADD DELETE RENAME NAME PRIVS QUIET NOISY DECOMPILE DESCRIBE CHOWN WIPE MUTE UNMUTE GAG UNGAG HIDE UNHIDE WHAT TITLE BRIEF RECALL BUFFER SET OBJECT", @@ -91,9 +109,11 @@ COMLIST commands[] = { {"@CHZONE", NULL, cmd_chzone, CMD_T_ANY | CMD_T_EQSPLIT | CMD_T_NOGAGGED, NULL}, + /* TODO: Re-enable CobraMUSH Channel Objects #ifdef CHAT_SYSTEM {"@COBJ", "RESET", cmd_cobj, CMD_T_ANY | CMD_T_EQSPLIT | CMD_T_NOGAGGED , NULL}, -#endif /* CHAT_SYSTEM */ +#endif CHAT_SYSTEM +*/ {"@CONFIG", "SET LOWERCASE LIST GLOBALS DEFAULTS COSTS FLAGS POWERS FUNCTIONS COMMANDS ATTRIBS", cmd_config, CMD_T_ANY | CMD_T_EQSPLIT, NULL}, @@ -152,11 +172,11 @@ COMLIST commands[] = { {"@FORCE", "NOEVAL", cmd_force, CMD_T_ANY | CMD_T_EQSPLIT | CMD_T_NOGAGGED, NULL}, - {"@FUNCTION", "DELETE ENABLE DISABLE PRESERVE RESTORE RESTRICT", cmd_function, + {"@FUNCTION", "BUILTIN DELETE ENABLE DISABLE PRESERVE RESTORE RESTRICT", cmd_function, CMD_T_ANY | CMD_T_EQSPLIT | CMD_T_RS_ARGS | CMD_T_NOGAGGED, NULL}, {"@GREP", "LIST PRINT ILIST IPRINT", cmd_grep, CMD_T_ANY | CMD_T_EQSPLIT | CMD_T_RS_NOPARSE | CMD_T_NOGAGGED, NULL}, - {"@HALT", "ALL", cmd_halt, CMD_T_ANY | CMD_T_EQSPLIT, NULL}, + {"@HALT", "ALL PID", cmd_halt, CMD_T_ANY | CMD_T_EQSPLIT, NULL}, {"@HIDE", "NO OFF YES ON", cmd_hide, CMD_T_ANY, NULL}, {"@HOOK", "LIST AFTER BEFORE IGNORE OVERRIDE", cmd_hook, CMD_T_ANY | CMD_T_EQSPLIT | CMD_T_RS_ARGS, @@ -191,6 +211,7 @@ COMLIST commands[] = { #endif {"@MAP", "DELIMIT", cmd_map, CMD_T_ANY | CMD_T_EQSPLIT | CMD_T_RS_NOPARSE, NULL}, + {"@MESSAGE", "NOEVAL SPOOF", cmd_message, CMD_T_ANY | CMD_T_EQSPLIT | CMD_T_RS_ARGS, NULL}, {"@MODULE", "LOAD UNLOAD", cmd_module, CMD_T_ANY, "POWER^SITE"}, {"@MOTD", "CONNECT LIST DOWN FULL", cmd_motd, CMD_T_ANY | CMD_T_NOGAGGED, NULL}, @@ -258,7 +279,7 @@ COMLIST commands[] = { CMD_T_ANY | CMD_T_EQSPLIT | CMD_T_RS_ARGS | CMD_T_RS_NOPARSE, NULL}, {"@SET", NULL, cmd_set, CMD_T_ANY | CMD_T_EQSPLIT | CMD_T_NOGAGGED, NULL}, {"@SHUTDOWN", "PANIC REBOOT PARANOID", cmd_shutdown, CMD_T_ANY, "POWER^Site"}, -#ifdef HAS_MYSQL +#if defined(HAVE_MYSQL) || defined(HAVE_POSTGRESQL) || defined(HAVE_SQLITE3) {"@SQL", NULL, cmd_sql, CMD_T_ANY, "POWER^SQL_OK"}, #else {"@SQL", NULL, cmd_unimplemented, CMD_T_ANY, "POWER^SQL_OK"}, @@ -288,11 +309,11 @@ COMLIST commands[] = { {"@UNLOCK", NULL, cmd_unlock, CMD_T_ANY | CMD_T_EQSPLIT | CMD_T_SWITCHES | CMD_T_NOGAGGED, NULL}, {"@UNRECYCLE", NULL, cmd_undestroy, CMD_T_ANY | CMD_T_NOGAGGED, NULL}, - {"@UPTIME", "MORTAL", cmd_uptime, CMD_T_ANY, NULL}, + {"@UPTIME", NULL, cmd_uptime, CMD_T_ANY, NULL}, {"@UUNLOCK", NULL, cmd_uunlock, CMD_T_ANY | CMD_T_NOGAGGED, NULL}, {"@VERB", NULL, cmd_verb, CMD_T_ANY | CMD_T_EQSPLIT | CMD_T_RS_ARGS, NULL}, {"@VERSION", NULL, cmd_version, CMD_T_ANY, NULL}, - {"@WAIT", "UNTIL", cmd_wait, CMD_T_ANY | CMD_T_EQSPLIT | CMD_T_RS_NOPARSE, + {"@WAIT", "PID UNTIL", cmd_wait, CMD_T_ANY | CMD_T_EQSPLIT | CMD_T_RS_NOPARSE, NULL}, {"@WALL", "NOEVAL EMIT", cmd_wall, CMD_T_ANY, "POWER^ANNOUNCE"}, @@ -402,7 +423,6 @@ struct command_perms_t command_perms[] = { {NULL, 0} }; - static void strccat(char *buff, char **bp, const char *from) { @@ -410,34 +430,60 @@ strccat(char *buff, char **bp, const char *from) safe_str(", ", buff, bp); safe_str(from, buff, bp); } +/* Comparison function for bsearch() */ +static int +switch_cmp(const void *a, const void *b) +{ + const char *name = a; + const SWITCH_VALUE *sw = b; + return strcmp(name, sw->name); +} + +/* This has different semantics than a prefix table, or we'd use that. */ static int -switch_find(COMMAND_INFO *cmd, char *sw) - { +switch_find(COMMAND_INFO *cmd, const char *sw) +{ SWITCH_VALUE *sw_val; - int len; - if (!sw || !*sw) + if (!sw || !*sw || !dyn_switch_list) return 0; - len = strlen(sw); - /* Special case, for init */ - sw_val = switch_list; + if (!cmd) { - while (sw_val->name) { - if (strcmp(sw_val->name, sw) == 0) - return sw_val->value; - sw_val++; - } - return 0; + sw_val = bsearch(sw, dyn_switch_list, num_switches, sizeof(SWITCH_VALUE), + switch_cmp); + if (sw_val) + return sw_val->value; + else + return 0; } else { + size_t len = strlen(sw); + if (!cmd->sw.mask) + return 0; + sw_val = dyn_switch_list; while (sw_val->name) { - if (SW_ISSET(cmd->sw, sw_val->value) && (strncmp(sw_val->name, sw, len) == 0)) - return sw_val->value; + if (SW_ISSET(cmd->sw.mask, sw_val->value) + && (strncmp(sw_val->name, sw, len) == 0)) + return sw_val->value; sw_val++; } } return 0; } +/** Test if a particular switch was given, using name + * \param sw the switch mask to test + * \param name the name of the switch to test for. + */ +bool +SW_BY_NAME(switch_mask sw, const char *name) +{ + int idx = switch_find(NULL, name); + if (idx) + return SW_ISSET(sw, idx); + else + return false; +} + /** Allocate and populate a COMMAND_INFO structure. * This function generates a new COMMAND_INFO structure, populates it * with given values, and returns a pointer. It should not be used @@ -451,20 +497,42 @@ switch_find(COMMAND_INFO *cmd, char *sw) * \return pointer to a newly allocated COMMAND_INFO structure. */ COMMAND_INFO * -make_command(const char *name, int type, switch_mask *sw, command_func func, const char *command_lock) +make_command(const char *name, int type, const char *sw, command_func func, const char *command_lock) { COMMAND_INFO *cmd; - cmd = (COMMAND_INFO *) mush_malloc(sizeof(COMMAND_INFO), "command"); + cmd = slab_malloc(command_slab, NULL); memset(cmd, 0, sizeof(COMMAND_INFO)); cmd->name = name; cmd->restrict_message = NULL; cmd->func = func; cmd->type = type; cmd->lock = !command_lock ? TRUE_BOOLEXP : parse_boolexp(GOD, command_lock, "Command_Lock"); - if (sw) - memcpy(cmd->sw, sw, sizeof(switch_mask)); - else - SW_ZERO(cmd->sw); + switch (command_state) { + case CMD_LOAD_BUILTIN: + cmd->sw.names = sw; + break; + case CMD_LOAD_LOCAL:{ + char sw_copy[BUFFER_LEN]; + char *pos; + cmd->sw.names = sw; + mush_strncpy(sw_copy, sw, BUFFER_LEN); + pos = sw_copy; + while (pos) { + char *thisone = split_token(&pos, ' '); + st_insert(thisone, &switch_names); + } + break; + } + case CMD_LOAD_DONE:{ + switch_mask mask = switchmask(sw); + if (mask) { + cmd->sw.mask = SW_ALLOC(); + SW_COPY(cmd->sw.mask, mask); + } else + cmd->sw.mask = NULL; + } + } + cmd->hooks.before.obj = NOTHING; cmd->hooks.before.attrname = NULL; cmd->hooks.after.obj = NOTHING; @@ -488,12 +556,9 @@ make_command(const char *name, int type, switch_mask *sw, command_func func, con COMMAND_INFO * command_add(const char *name, int type, const char *switchstr, command_func func, const char *command_lock) { - switch_mask *sw = switchmask(switchstr); - ptab_start_inserts(&ptab_command); - ptab_insert(&ptab_command, name, - make_command(name, type, sw, func, command_lock)); - ptab_end_inserts(&ptab_command); + ptab_insert_one(&ptab_command, name, + make_command(name, type, switchstr, func, command_lock)); return command_find(name); } @@ -551,7 +616,7 @@ command_find_exact(const char *name) * \return pointer to modified command entry, or NULL. */ COMMAND_INFO * -command_modify(const char *name, int type, const char *command_lock, switch_mask *sw, command_func func) +command_modify(const char *name, int type, const char *command_lock, switch_mask sw, command_func func) { COMMAND_INFO *cmd; cmd = command_find(name); @@ -565,7 +630,7 @@ command_modify(const char *name, int type, const char *command_lock, switch_mask cmd->lock = parse_boolexp(GOD, command_lock, "Command_Lock"); } if (sw) - memcpy(cmd->sw, sw, sizeof(switch_mask)); + SW_COPY(cmd->sw.mask, sw); if (func) cmd->func = func; return cmd; @@ -577,13 +642,20 @@ command_modify(const char *name, int type, const char *command_lock, switch_mask * \param switches list of switches as a string. * \return pointer to a static switch mask. */ -switch_mask * -switchmask(const char *switches) +switch_mask +*switchmask(const char *switches) { - static switch_mask sw; + static switch_mask sw = NULL; + static int sm_bytes = 0; char buff[BUFFER_LEN]; char *p, *s; int switchnum; + + if (sm_bytes < switch_bytes) { + sw = mush_realloc(sw, switch_bytes, "cmd.switch.vector"); + sm_bytes = switch_bytes; + } + SW_ZERO(sw); if (!switches || !switches[0]) return NULL; @@ -597,7 +669,7 @@ switchmask(const char *switches) else SW_SET(sw, switchnum); } - return &sw; + return sw; } /** Add an alias to the table of reserved aliases. @@ -614,6 +686,8 @@ reserve_alias(const char *a) hashadd(strupper(a), (void *) placeholder, &htab_reserved_aliases); } +static StrTree switch_names; + /** Initialize command tables (before reading config file). * This function performs command table initialization that should take place * before the configuration file has been read. It initializes the @@ -628,18 +702,39 @@ command_init_preconfig(void) { struct command_perms_t *c; COMLIST *cmd; + SWITCH_VALUE *sv; static int done = 0; if (done == 1) return; done = 1; ptab_init(&ptab_command); - hashinit(&htab_reserved_aliases, 16, sizeof(COMMAND_INFO)); + hashinit(&htab_reserved_aliases, 16); + + /* Build initial switch table. */ + st_init(&switch_names); + for (sv = switch_list; sv->name; sv++) + st_insert(sv->name, &switch_names); + + command_slab = slab_create("commands", sizeof(COMMAND_INFO)); + /* reserve_aliases(); this can now be handeled in respective modules */ ptab_start_inserts(&ptab_command); + command_state = CMD_LOAD_BUILTIN; for (cmd = commands; cmd->name; cmd++) { + if (cmd->switches) { + char sw_copy[BUFFER_LEN]; + char *pos; + strcpy(sw_copy, cmd->switches); + pos = sw_copy; + while (pos) { + char *sw = split_token(&pos, ' '); + st_insert(sw, &switch_names); + } + } + ptab_insert(&ptab_command, cmd->name, - make_command(cmd->name, cmd->type, switchmask(cmd->switches), + make_command(cmd->name, cmd->type, cmd->switches, cmd->func, cmd->command_lock)); } ptab_end_inserts(&ptab_command); @@ -650,9 +745,35 @@ command_init_preconfig(void) ptab_insert(&ptab_command_perms, c->name, c); ptab_end_inserts(&ptab_command_perms); + command_state = CMD_LOAD_LOCAL; /* no longer needed with modules. local_commands(); */ } +struct bst_data { + SWITCH_VALUE *table; + size_t n; + size_t start; +}; + +static void +build_switch_table(const char *sw, int count __attribute__ ((__unused__)), + void *d) +{ + SWITCH_VALUE *s; + struct bst_data *data = d; + + for (s = switch_list; s->name; s++) { + if (strcmp(s->name, sw) == 0) { + data->table[data->n++] = *s; + return; + } + } + /* Not in switchinc.c table */ + data->table[data->n].value = data->start++; + data->table[data->n++].name = mush_strdup(sw, "switch.name"); +} + + /** Initialize commands (after reading config file). * This function performs command initialization that should take place * after the configuration file has been read. @@ -661,6 +782,36 @@ command_init_preconfig(void) void command_init_postconfig(void) { + struct bst_data sw_data; + COMMAND_INFO *c; + size_t sl_size; + + command_state = CMD_LOAD_DONE; + + /* First make the switch table */ + dyn_switch_list = mush_calloc(switch_names.count + 2, sizeof(SWITCH_VALUE), + "cmd_switch_table"); + if (!dyn_switch_list) + mush_panic(T("Unable to allocate command switch table")); + sw_data.table = dyn_switch_list; + sw_data.n = 0; + sw_data.start = sizeof switch_list / sizeof(SWITCH_VALUE); + sl_size = sw_data.start - 2; + st_walk(&switch_names, build_switch_table, &sw_data); + num_switches = sw_data.start; + dyn_switch_list[sw_data.n].name = NULL; + st_flush(&switch_names); + switch_bytes = ceil((double) num_switches / 8.0); + + /* Then convert the list of switch names in all commands to masks */ + for (c = ptab_firstentry(&ptab_command); c; c = ptab_nextentry(&ptab_command)) { + const char *switchstr = c->sw.names; + if (switchstr) { + c->sw.mask = SW_ALLOC(); + SW_COPY(c->sw.mask, switchmask(switchstr)); + } + } + return; } @@ -686,9 +837,7 @@ alias_command(const char *command, const char *alias) if (!cmd) return 0; - ptab_start_inserts(&ptab_command); - ptab_insert(&ptab_command, strupper(alias), cmd); - ptab_end_inserts(&ptab_command); + ptab_insert_one(&ptab_command, strupper(alias), cmd); return 1; } @@ -763,8 +912,9 @@ command_argparse(dbref player, dbref realcause, dbref cause, char **from, char * aold = t; while (*f == ' ') f++; - process_expression(to, &t, (const char **) &f, player, realcause, cause, - parse, (split | args), NULL); + if(process_expression(to, &t, (const char **) &f, player, realcause, cause, + parse, (split | args), NULL)) + done = 1; *t = '\0'; if (args) { argv[i] = aold; @@ -864,7 +1014,7 @@ command_parse(dbref player, dbref cause, dbref realcause, char *string, int from char command2[BUFFER_LEN]; char b; int switchnum; - switch_mask sw; + switch_mask sw = NULL; char switch_err[BUFFER_LEN], *se; int noeval; int noevtoken = 0; @@ -872,11 +1022,11 @@ command_parse(dbref player, dbref cause, dbref realcause, char *string, int from rhs_present = 0; - command = (char *) mush_malloc(BUFFER_LEN, "string"); - swtch = (char *) mush_malloc(BUFFER_LEN, "string"); - ls = (char *) mush_malloc(BUFFER_LEN, "string"); - rs = (char *) mush_malloc(BUFFER_LEN, "string"); - switches = (char *) mush_malloc(BUFFER_LEN, "string"); + command = mush_malloc(BUFFER_LEN, "string"); + swtch = mush_malloc(BUFFER_LEN, "string"); + ls = mush_malloc(BUFFER_LEN, "string"); + rs = mush_malloc(BUFFER_LEN, "string"); + switches = mush_malloc(BUFFER_LEN, "string"); if (!command || !swtch || !ls || !rs || !switches) mush_panic("Couldn't allocate memory in command_parse"); p = string; @@ -1054,7 +1204,7 @@ command_parse(dbref player, dbref cause, dbref realcause, char *string, int from } /* Parse out any switches */ - SW_ZERO(sw); + sw = SW_ALLOC(); swp = switches; *swp = '\0'; se = switch_err; @@ -1200,9 +1350,7 @@ command_parse(dbref player, dbref cause, dbref realcause, char *string, int from /* If we have a hook/ignore that returns false, we don't do the command */ if (run_hook(player, cause, &cmd->hooks.ignore, saveregs, 1)) { /* If we have a hook/override, we use that instead */ - if (!has_hook(&cmd->hooks.override) || - !one_comm_match(cmd->hooks.override.obj, player, - cmd->hooks.override.attrname, commandraw)) { + if (!run_hook_override(cmd, player, commandraw)) { /* Otherwise, we do hook/before, the command, and hook/after */ /* But first, let's see if we had an invalid switch */ if (*switch_err) { @@ -1226,6 +1374,7 @@ command_parse(dbref player, dbref cause, dbref realcause, char *string, int from free_global_regs("hook.regs", saveregs); } + SW_FREE(sw); command_parse_free_args; return retval; } @@ -1290,23 +1439,23 @@ generic_command_failure(dbref player, dbref cause, char *string, int fromport) * \retval 0 failure (unable to find command name). */ int -restrict_command(const char *name, const char *restriction) +restrict_command(const char *name, const char *xrestriction) { COMMAND_INFO *command; struct command_perms_t *c; - char *message; + char *message, *restriction, *rsave; int clear; char *tp; - if (!name || !*name || !restriction || !*restriction || + if (!name || !*name || !xrestriction || !*xrestriction || !(command = command_find(name))) return 0; if (command->restrict_message) { - mush_free((Malloc_t) command->restrict_message, "cmd_restrict_message"); + mush_free((void *) command->restrict_message, "cmd_restrict_message"); command->restrict_message = NULL; } - + rsave = restriction = mush_strdup(xrestriction, "rc.string"); message = strchr(restriction, '"'); if (message) { *(message++) = '\0'; @@ -1338,6 +1487,7 @@ restrict_command(const char *name, const char *restriction) } restriction = tp; } + mush_free(rsave, "rc.string"); return 1; } @@ -1481,8 +1631,8 @@ do_command_delete(dbref player, char *name) } else cptr = ptab_nextentry_new(&ptab_command, alias); } - mush_free((Malloc_t) command->name, "command_add"); - mush_free((Malloc_t) command, "command"); + mush_free((void *) command->name, "command_add"); + slab_free(command_slab, command); if (acount > 1) notify_format(player, T("Removed %s and aliases from command table."), name); else @@ -1499,7 +1649,8 @@ do_command_delete(dbref player, char *name) * This is the only command which should be defined in this * file, because it uses variables from this file, etc. */ -COMMAND (cmd_command) { +COMMAND(cmd_command) +{ COMMAND_INFO *command; SWITCH_VALUE *sw_val; char buff[BUFFER_LEN]; @@ -1634,12 +1785,15 @@ COMMAND (cmd_command) { notify_format(player, "Restrict : %s", buff); buff[0] = '\0'; notify_format(player, "Command Lock : %s", unparse_boolexp(player, command->lock, UB_MEREF)); - bp = buff; - for (sw_val = switch_list; sw_val->name; sw_val++) - if (SW_ISSET(command->sw, sw_val->value)) - strccat(buff, &bp, sw_val->name); - *bp = '\0'; - notify_format(player, "Switches : %s", buff); + if (command->sw.mask) { + bp = buff; + for (sw_val = dyn_switch_list; sw_val->name; sw_val++) + if (SW_ISSET(command->sw.mask, sw_val->value)) + strccat(buff, &bp, sw_val->name); + *bp = '\0'; + notify_format(player, "Switches : %s", buff); + } else + notify(player, "Switches :"); buff[0] = '\0'; bp = buff; if (command->type & CMD_T_LS_ARGS) { @@ -1682,7 +1836,7 @@ void do_list_commands(dbref player, int lc) { char *b = list_commands(); - notify_format(player, "Commands: %s", lc ? strlower(b) : b); + notify_format(player, T("Commands: %s"), lc ? strlower(b) : b); } /** Return a list of defined commands. @@ -1692,21 +1846,24 @@ char * list_commands(void) { COMMAND_INFO *command; - const char *ptrs[BUFFER_LEN / 2]; + char *ptrs[BUFFER_LEN / 2]; static char buff[BUFFER_LEN]; char *bp; int nptrs = 0, i; command = (COMMAND_INFO *) ptab_firstentry(&ptab_command); while (command) { - ptrs[nptrs] = command->name; + ptrs[nptrs] = (char *) command->name; nptrs++; command = (COMMAND_INFO *) ptab_nextentry(&ptab_command); } + do_gensort(0, ptrs, NULL, nptrs, ALPHANUM_LIST); bp = buff; safe_str(ptrs[0], buff, &bp); for (i = 1; i < nptrs; i++) { + if (gencomp((dbref) 0, ptrs[i], ptrs[i - 1], ALPHANUM_LIST) > 0) { safe_chr(' ', buff, &bp); safe_str(ptrs[i], buff, &bp); + } } *bp = '\0'; return buff; @@ -1813,8 +1970,7 @@ command_check_byname(dbref player, const char *name) static int has_hook(struct hook_data *hook) { - if (!hook || !GoodObject(hook->obj) || IsGarbage(hook->obj) - || !hook->attrname) + if (!hook || !GoodObject(hook->obj) || IsGarbage(hook->obj)) return 0; return 1; } @@ -1871,6 +2027,22 @@ run_hook(dbref player, dbref cause, struct hook_data *hook, char *saveregs[], return parse_boolean(buff); } +int +run_hook_override(COMMAND_INFO *cmd, dbref player, const char *commandraw) +{ + + if (!has_hook(&cmd->hooks.override)) + return 0; + + if (cmd->hooks.override.attrname) { + return one_comm_match(cmd->hooks.override.obj, player, + cmd->hooks.override.attrname, commandraw); + } else { + return atr_comm_match(cmd->hooks.override.obj, player, '$', ':', commandraw, + 0, NULL, NULL, NULL); + } +} + /** Set up or remove a command hook. * \verbatim * This is the top-level function for @hook. If an object and attribute @@ -1917,8 +2089,13 @@ do_hook(dbref player, char *command, char *obj, char *attrname, h->obj = NOTHING; mush_free(h->attrname, "hook.attr"); h->attrname = NULL; - } else if (!obj || !*obj || !attrname || !*attrname) { - notify(player, T("You must give both an object and attribute.")); + } else if (!obj || !*obj + || (flag != HOOK_OVERRIDE && (!attrname || !*attrname))) { + if (flag == HOOK_OVERRIDE) { + notify(player, T("You must give an object.")); + } else { + notify(player, T("You must give both an object and attribute.")); + } } else { dbref objdb = match_thing(player, obj); if (!GoodObject(objdb)) { @@ -1928,7 +2105,11 @@ do_hook(dbref player, char *command, char *obj, char *attrname, h->obj = objdb; if (h->attrname) mush_free(h->attrname, "hook.attr"); - h->attrname = mush_strdup(strupper(attrname), "hook.attr"); + if (!attrname || !*attrname) { + h->attrname = NULL; + } else { + h->attrname = mush_strdup(strupper(attrname), "hook.attr"); + } notify_format(player, T("Hook set for %s"), cmd->name); } } @@ -1954,16 +2135,16 @@ do_hook_list(dbref player, char *command) } if (Site(player)) { if (GoodObject(cmd->hooks.before.obj)) - notify_format(player, "@hook/before: #%d/%s", + notify_format(player, T("@hook/before: #%d/%s"), cmd->hooks.before.obj, cmd->hooks.before.attrname); if (GoodObject(cmd->hooks.after.obj)) - notify_format(player, "@hook/after: #%d/%s", cmd->hooks.after.obj, + notify_format(player, T("@hook/after: #%d/%s"), cmd->hooks.after.obj, cmd->hooks.after.attrname); if (GoodObject(cmd->hooks.ignore.obj)) - notify_format(player, "@hook/ignore: #%d/%s", + notify_format(player, T("@hook/ignore: #%d/%s"), cmd->hooks.ignore.obj, cmd->hooks.ignore.attrname); if (GoodObject(cmd->hooks.override.obj)) - notify_format(player, "@hook/override: #%d/%s", + notify_format(player, T("@hook/override: #%d/%s"), cmd->hooks.override.obj, cmd->hooks.override.attrname); } } diff --git a/src/comp_h.c b/src/comp_h.c index ba26fe3..104fcee 100644 --- a/src/comp_h.c +++ b/src/comp_h.c @@ -54,6 +54,8 @@ static CNode *ctop; static CType ctable[TABLE_SIZE]; static char ltable[TABLE_SIZE]; +slab *huffman_slab = NULL; + static int fix_tree_depth(CNode *node, int height, int zeros); static void add_ones(CNode *node); static void build_ctable(CNode *root, CType code, int numbits); @@ -76,7 +78,7 @@ int init_compress(FILE * f); * \return newly allocated compressed string. */ unsigned char * -compress(const char *s) +text_compress(const char *s) { CType stage; int bits = 0; @@ -153,7 +155,7 @@ do { \ * used with something of the format * \verbatim * char tbuf1[BUFFER_LEN]; - * strcpy(tbuf1, uncompress(a->value)); + * strcpy(tbuf1, text_uncompress(a->value)); * \endverbatim * if you are using something of type char *buff, use the * safe_uncompress function instead. @@ -162,7 +164,7 @@ do { \ * \return a pointer to a static buffer containing the uncompressed string. */ char * -uncompress(const unsigned char *s) +text_uncompress(const unsigned char *s) { static char buf[BUFFER_LEN]; @@ -259,7 +261,7 @@ add_ones(CNode *node) if (node->right) add_ones(node->right); if ((count >= 7) || ((count >= 3) && !node->left && !node->right)) { - ctop = (CNode *) malloc((unsigned) sizeof(CNode)); + ctop = slab_malloc(huffman_slab, node); if (!ctop) { do_rawlog(LT_ERR, "Cannot allocate memory for compression tree. Aborting."); @@ -336,10 +338,13 @@ init_compress(FILE * f) printf("init_compress: Part 1\n"); #endif + huffman_slab = slab_create("huffman attribute compression", sizeof(CNode)); + slab_set_opt(huffman_slab, SLAB_ALLOC_BEST_FIT, 1); + /* Part 1: initialize */ for (total = 0; total < TABLE_SIZE; total++) { table[total].freq = 0; - table[total].node = (CNode *) malloc((unsigned) sizeof(CNode)); + table[total].node = slab_malloc(huffman_slab, NULL); if (!table[total].node) { do_rawlog(LT_ERR, "Cannot allocate memory for compression tree. Aborting."); @@ -434,7 +439,7 @@ init_compress(FILE * f) printf("%3d: %d\t", table[count].node->c, table[count].freq); printf("\n"); #endif - node = (CNode *) malloc((unsigned) sizeof(CNode)); + node = slab_malloc(huffman_slab, table[indx].node); if (!node) { do_rawlog(LT_ERR, "Cannot allocate memory for compression tree. Aborting."); @@ -484,7 +489,7 @@ init_compress(FILE * f) node = table[1].node; /* top of tree */ for (count = 0; node->left && (count < 4); count++) node = node->left; - ctop = (CNode *) malloc((unsigned) sizeof(CNode)); + ctop = slab_malloc(huffman_slab, node); if (!ctop) { do_rawlog(LT_ERR, "Cannot allocate memory for compression tree. Aborting."); exit(1); @@ -508,7 +513,7 @@ init_compress(FILE * f) node = table[1].node; /* top of tree */ for (count = 0; count < 8; count++) { if (!node->left) { - ctop = (CNode *) malloc((unsigned) sizeof(CNode)); + ctop = slab_malloc(huffman_slab, node); if (!ctop) { do_rawlog(LT_ERR, "Cannot allocate memory for compression tree. Aborting."); diff --git a/src/comp_w.c b/src/comp_w.c index d3b0305..331ca8e 100644 --- a/src/comp_w.c +++ b/src/comp_w.c @@ -125,6 +125,7 @@ #include "externs.h" #include "mushdb.h" #include "mymalloc.h" +#include "dbio.h" #include "confmagic.h" #define MAXTABLE 32768 /**< Maximum words in the table */ @@ -159,7 +160,7 @@ static long total_entries = 0; static unsigned char *b; static void output_previous_word(void); -int init_compress(FILE * f); +int init_compress(FILE *f); #ifdef COMP_STATS void compress_stats(long *entries, long *mem_used, long *total_uncompressed, long *total_compressed); @@ -237,7 +238,7 @@ output_previous_word(void) * \return newly allocated compressed string. */ unsigned char * -compress(char const *s) +text_compress(char const *s) { const unsigned char *p; static unsigned char buf[BUFFER_LEN]; @@ -249,7 +250,7 @@ compress(char const *s) /* break up input into words */ while (*p) { - if (!(isdigit(*p) || isalpha(*p)) || wordpos >= MAXWORDS) { + if (!isalnum(*p) || wordpos >= MAXWORDS) { if (wordpos) { word[wordpos++] = *p & 0x7F; /* add trailing punctuation */ output_previous_word(); @@ -280,7 +281,7 @@ compress(char const *s) * used with something of the format * \verbatim * char tbuf1[BUFFER_LEN]; - * strcpy(tbuf1, uncompress(a->value)); + * strcpy(tbuf1, text_uncompress(a->value)); * \endverbatim * if you are using something of type char *buff, use the * safe_uncompress function instead. @@ -289,7 +290,7 @@ compress(char const *s) * \return a pointer to a static buffer containing the uncompressed string. */ char * -uncompress(unsigned char const *s) +text_uncompress(unsigned char const *s) { const unsigned char *p; @@ -301,7 +302,7 @@ uncompress(unsigned char const *s) if (!s || !*s) return buf; p = (unsigned char *) s; - b = (unsigned char *) buf; + b = buf; while (*p) { c = *p; @@ -359,7 +360,7 @@ safe_uncompress(unsigned char const *s) * \param f (unused). */ int -init_compress(FILE * f __attribute__ ((__unused__))) +init_compress(FILE *f __attribute__ ((__unused__))) { memset(words, 0, sizeof words); memset(words_len, 0, sizeof words_len); diff --git a/src/comp_w8.c b/src/comp_w8.c index 284582b..cfd4abd 100644 --- a/src/comp_w8.c +++ b/src/comp_w8.c @@ -241,19 +241,19 @@ output_previous_word(void) * \return newly allocated compressed string. */ unsigned char * -compress(char const *s) +text_compress(char const *s) { const unsigned char *p; - static char buf[BUFFER_LEN]; + static unsigned char buf[BUFFER_LEN]; p = (unsigned char *) s; - b = (unsigned char *) buf; + b = buf; wordpos = 0; /* break up input into words */ while (*p) { - if (!(isdigit(*p) || isalpha(*p)) || wordpos >= MAXWORDS) { + if (!isalnum(*p) || wordpos >= MAXWORDS) { if (wordpos) { word[wordpos++] = *p; /* add trailing punctuation */ output_previous_word(); @@ -284,7 +284,7 @@ compress(char const *s) * used with something of the format * \verbatim * char tbuf1[BUFFER_LEN]; - * strcpy(tbuf1, uncompress(a->value)); + * strcpy(tbuf1, text_uncompress(a->value)); * \endverbatim * if you are using something of type char *buff, use the * safe_uncompress function instead. @@ -293,7 +293,7 @@ compress(char const *s) * \return a pointer to a static buffer containing the uncompressed string. */ char * -uncompress(unsigned char const *s) +text_uncompress(unsigned char const *s) { const unsigned char *p; @@ -305,7 +305,7 @@ uncompress(unsigned char const *s) if (!s || !*s) return buf; p = (unsigned char *) s; - b = buf; + b = (unsigned char *) buf; while (*p) { c = *p; diff --git a/src/compress.c b/src/compress.c index c23a047..22ec712 100644 --- a/src/compress.c +++ b/src/compress.c @@ -10,7 +10,7 @@ #include "config.h" #include "options.h" - +#include /* It's rather dumb mushtype.h has to be included */ #include "mushtype.h" #include "log.h" diff --git a/src/conf.c b/src/conf.c index 9ec3bf7..b5721c4 100644 --- a/src/conf.c +++ b/src/conf.c @@ -14,6 +14,9 @@ #include #ifdef I_SYS_TIME #include +#ifdef TIME_WITH_SYS_TIME +#include +#endif #else #include #endif @@ -23,6 +26,7 @@ #include "conf.h" #include "externs.h" +#include "ansi.h" #include "pueblo.h" #include "mushdb.h" #include "parse.h" @@ -163,13 +167,13 @@ COBRA_CONF conftable[] = { , {"zone_control_zmp_only", cf_bool, &options.zone_control, 2, 0, "db"} , - {"ancestor_room", cf_int, &options.ancestor_room, 100000, 0, "db"} + {"ancestor_room", cf_dbref, &options.ancestor_room, 100000, 0, "db"} , - {"ancestor_exit", cf_int, &options.ancestor_exit, 100000, 0, "db"} + {"ancestor_exit", cf_dbref, &options.ancestor_exit, 100000, 0, "db"} , - {"ancestor_thing", cf_int, &options.ancestor_thing, 100000, 0, "db"} + {"ancestor_thing", cf_dbref, &options.ancestor_thing, 100000, 0, "db"} , - {"ancestor_player", cf_int, &options.ancestor_player, 100000, 0, "db"} + {"ancestor_player", cf_dbref, &options.ancestor_player, 100000, 0, "db"} , {"powerless", cf_int, &options.powerless, 100000, 0, "db"} , @@ -197,7 +201,6 @@ COBRA_CONF conftable[] = { , {"pueblo", cf_bool, &options.support_pueblo, 2, 0, "net"} , -#ifdef HAS_MYSQL {"sql_platform", cf_str, options.sql_platform, sizeof options.sql_platform, 0, "net"} , @@ -212,8 +215,6 @@ COBRA_CONF conftable[] = { {"sql_database", cf_str, options.sql_database, sizeof options.sql_database, 0, NULL} , -#endif - {"forking_dump", cf_bool, &options.forking_dump, 2, 0, "dump"} , {"dump_message", cf_str, options.dump_message, sizeof options.dump_message, 0, @@ -353,7 +354,8 @@ COBRA_CONF conftable[] = { , {"chan_cost", cf_int, &options.chan_cost, 10000, 0, "chat"} , - + {"noisy_cemit", cf_bool, &options.noisy_cemit, 2, 0, "chat"} + , {"log_commands", cf_bool, &options.log_commands, 2, 0, "log"} , {"log_forces", cf_bool, &options.log_forces, 2, 0, "log"} @@ -601,13 +603,13 @@ get_config(const char *name) * \param val value of the option. * \param loc address to store the value. * \param maxval (unused). - * \param source 0 if read from config file; 1 if from command. + * \param from_cmd 0 if read from config file; 1 if from command. * \retval 0 failure (unable to parse val). * \retval 1 success. */ int cf_bool(const char *opt, const char *val, void *loc, - int maxval __attribute__ ((__unused__)), int source) + int maxval __attribute__ ((__unused__)), int from_cmd) { /* enter boolean parameter */ @@ -618,8 +620,8 @@ cf_bool(const char *opt, const char *val, void *loc, !strcasecmp(val, "0")) *((int *) loc) = 0; else { - if (source == 0) { - do_rawlog(LT_ERR, T("CONFIG: option %s value %s invalid.\n"), opt, val); + if (from_cmd == 0) { + do_rawlog(LT_ERR, T("CONFIG: option %s value %s invalid."), opt, val); } return 0; } @@ -632,20 +634,20 @@ cf_bool(const char *opt, const char *val, void *loc, * \param val value of the option. * \param loc address to store the value. * \param maxval maximum length of value string. - * \param source 0 if read from config file; 1 if from command. + * \param from_cmd 0 if read from config file; 1 if from command. * \retval 0 failure (unable to parse val). * \retval 1 success. */ int -cf_str(const char *opt, const char *val, void *loc, int maxval, int source) +cf_str(const char *opt, const char *val, void *loc, int maxval, int from_cmd) { /* enter string parameter */ size_t len = strlen(val); /* truncate if necessary */ if (len >= (size_t) maxval) { - if (source == 0) { - do_rawlog(LT_ERR, T("CONFIG: option %s value truncated\n"), opt); + if (from_cmd == 0) { + do_rawlog(LT_ERR, T("CONFIG: option %s value truncated"), opt); } len = maxval - 1; } @@ -655,19 +657,22 @@ cf_str(const char *opt, const char *val, void *loc, int maxval, int source) } /** Parse a dbref configuration option. + * dbrefs can be a raw number N or #N, even though # normally starts a comment + * in the config file. #-1 is allowed. Limits are -1 to db_max for @config, + * -1 to INT_MAX for reading mush.cnf (And validated elsewhere). * \param opt name of the configuration option. * \param val value of the option. * \param loc address to store the value. * \param maxval maximum dbref. - * \param source 0 if read from config file; 1 if from command. + * \param from_cmd 0 if read from config file; 1 if from command. * \retval 0 failure (unable to parse val). * \retval 1 success. */ int -cf_dbref(const char *opt, const char *val, void *loc, int maxval, int source) +cf_dbref(const char *opt, const char *val, void *loc, + int maxval __attribute__ ((__unused__)), int from_cmd) { /* enter dbref or integer parameter */ - int n; size_t offset = 0; @@ -677,14 +682,14 @@ cf_dbref(const char *opt, const char *val, void *loc, int maxval, int source) n = parse_integer(val + offset); /* enforce limits */ - if ((maxval >= 0) && (n > maxval)) { - n = maxval; - if (source == 0) { - do_rawlog(LT_ERR, T("CONFIG: option %s value limited to #%d\n"), opt, + if (n < NOTHING) { + n = NOTHING; + if (from_cmd == 0) { + do_rawlog(LT_ERR, T("CONFIG: option %s value limited to #%d"), opt, maxval); } } - if (source && (!GoodObject(n) || IsGarbage(n))) { + if (from_cmd && ((!GoodObject(n) && n != NOTHING) || (n > 0 && IsGarbage(n)))) { do_rawlog(LT_ERR, T("CONFIG: attempt to set option %s to a bad dbref (#%d)"), opt, n); @@ -699,12 +704,12 @@ cf_dbref(const char *opt, const char *val, void *loc, int maxval, int source) * \param val value of the option. * \param loc address to store the value. * \param maxval maximum value. - * \param source 0 if read from config file; 1 if from command. + * \param from_cmd 0 if read from config file; 1 if from command. * \retval 0 failure (unable to parse val). * \retval 1 success. */ int -cf_int(const char *opt, const char *val, void *loc, int maxval, int source) +cf_int(const char *opt, const char *val, void *loc, int maxval, int from_cmd) { /* enter integer parameter */ @@ -718,8 +723,8 @@ cf_int(const char *opt, const char *val, void *loc, int maxval, int source) /* enforce limits */ if ((maxval >= 0) && (n > maxval)) { n = maxval; - if (source == 0) { - do_rawlog(LT_ERR, T("CONFIG: option %s value limited to %d\n"), opt, + if (from_cmd == 0) { + do_rawlog(LT_ERR, T("CONFIG: option %s value limited to %d"), opt, maxval); } } @@ -733,12 +738,12 @@ cf_int(const char *opt, const char *val, void *loc, int maxval, int source) * \param val value of the option. * \param loc address to store the value. * \param maxval maximum value. - * \param source 0 if read from config file; 1 if from command. + * \param from_cmd 0 if read from config file; 1 if from command. * \retval 0 failure (unable to parse val). * \retval 1 success. */ int -cf_time(const char *opt, const char *val, void *loc, int maxval, int source) +cf_time(const char *opt, const char *val, void *loc, int maxval, int from_cmd) { /* enter time parameter */ char *end = NULL; @@ -750,7 +755,7 @@ cf_time(const char *opt, const char *val, void *loc, int maxval, int source) in_minutes = 1; while (val && *val) { - n = strtol(val, &end, 10); + n = parse_int(val, &end, 10); switch (*end) { case '\0': @@ -772,7 +777,7 @@ cf_time(const char *opt, const char *val, void *loc, int maxval, int source) secs += n * 3600; break; default: - if (source == 0) + if (from_cmd == 0) do_rawlog(LT_ERR, T("CONFIG: Unknown time interval in option %s"), opt); return 0; } @@ -782,8 +787,8 @@ done: /* enforce limits */ if ((maxval >= 0) && (secs > maxval)) { secs = maxval; - if (source == 0) { - do_rawlog(LT_ERR, T("CONFIG: option %s value limited to %d\n"), opt, + if (from_cmd == 0) { + do_rawlog(LT_ERR, T("CONFIG: option %s value limited to %d"), opt, maxval); } } @@ -798,12 +803,12 @@ done: * \param val value of the option. * \param loc address to store the value. * \param maxval maximum length of value. - * \param source 0 if read from config file; 1 if from command. + * \param from_cmd 0 if read from config file; 1 if from command. * \retval 0 failure (unable to parse val). * \retval 1 success. */ int -cf_flag(const char *opt, const char *val, void *loc, int maxval, int source) +cf_flag(const char *opt, const char *val, void *loc, int maxval, int from_cmd) { size_t len = strlen(val); size_t total = strlen((char *) loc); @@ -812,17 +817,55 @@ cf_flag(const char *opt, const char *val, void *loc, int maxval, int source) if (len + total + 1 >= (size_t) maxval) { len = maxval - total - 1; if (len <= 0) { - if (source == 0) - do_rawlog(LT_ERR, T("CONFIG: option %s value overflow\n"), opt); + if (from_cmd == 0) + do_rawlog(LT_ERR, T("CONFIG: option %s value overflow"), opt); return 0; } - if (source == 0) - do_rawlog(LT_ERR, T("CONFIG: option %s value truncated\n"), opt); + if (from_cmd == 0) + do_rawlog(LT_ERR, T("CONFIG: option %s value truncated"), opt); } sprintf((char *) loc, "%s %s", (char *) loc, val); return 1; } +/** Validate config options after reading the database. + * Used mostly for dbref options to make sure they point to valid + * objects. + */ +void +validate_config(void) +{ + +#define VALIDATE_ROOM(opt) do { \ + if (!(GoodObject((opt)) && IsRoom((opt)))) { \ + opt = 0; \ + do_rawlog(LT_ERR, T("CONFIG: option %s not a valid room!"), #opt); \ + } \ + } while (0) + + VALIDATE_ROOM(PLAYER_START); + VALIDATE_ROOM(MASTER_ROOM); + VALIDATE_ROOM(BASE_ROOM); + VALIDATE_ROOM(DEFAULT_HOME); + +#undef VALIDATE_ROOM + +#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!"), \ + #opt); \ + } \ + } while (0) + + VALIDATE(ANCESTOR_ROOM); + VALIDATE(ANCESTOR_THING); + VALIDATE(ANCESTOR_PLAYER); + VALIDATE(ANCESTOR_EXIT); + +#undef VALIDATE +} + /** Set a configuration option. * This function sets a runtime configuration option. During the load * of the configuration file, it gets run twice - once to set the @@ -872,7 +915,7 @@ config_set(const char *opt, char *val, int source, int restrictions) 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; } @@ -880,7 +923,7 @@ config_set(const char *opt, char *val, int source, int restrictions) 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; @@ -895,8 +938,7 @@ config_set(const char *opt, char *val, int source, int restrictions) 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; } @@ -904,7 +946,7 @@ config_set(const char *opt, char *val, int source, int restrictions) 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; @@ -923,14 +965,14 @@ config_set(const char *opt, char *val, int source, int restrictions) *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; } @@ -943,14 +985,14 @@ config_set(const char *opt, char *val, int source, int restrictions) *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; } @@ -963,14 +1005,14 @@ config_set(const char *opt, char *val, int source, int restrictions) *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; } @@ -987,7 +1029,7 @@ config_set(const char *opt, char *val, int source, int restrictions) 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; @@ -999,7 +1041,7 @@ config_set(const char *opt, char *val, int source, int restrictions) } 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) { @@ -1034,7 +1076,7 @@ config_set(const char *opt, char *val, int source, int restrictions) } 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; } @@ -1053,6 +1095,7 @@ conf_default_set(void) strcpy(options.chatdb, "data/chatdb"); strcpy(options.flagdb, "data/flagdb"); options.chan_cost = 1000; + options.noisy_cemit = 0; options.max_player_chans = 3; options.max_channels = 200; #ifdef USE_MAILER @@ -1219,13 +1262,14 @@ conf_default_set(void) options.ssl_require_client_cert = 0; #endif options.mem_check = 1; -#ifdef HAS_MYSQL + /* Set this to 1 so that allocations made before reading the config file + will be tracked. */ strcpy(options.sql_platform, "disabled"); strcpy(options.sql_database, ""); strcpy(options.sql_username, ""); strcpy(options.sql_password, ""); strcpy(options.sql_host, "127.0.0.1"); -#endif + /* Guest Options */ strcpy(options.guest_prefix, "Guest-"); /* Default to Regular Numbering */ @@ -1409,7 +1453,7 @@ do_config_list(dbref player, const char *type, int lc) COBRA_CONF *cp; if (SUPPORT_PUEBLO) - notify_noenter(player, tprintf("%cSAMP%c", TAG_START, TAG_END)); + notify_noenter(player, open_tag("SAMP")); if (type && *type) { /* Look up the type in the group table */ int found = 0; @@ -1475,7 +1519,7 @@ do_config_list(dbref player, const char *type, int lc) } } if (SUPPORT_PUEBLO) - notify_noenter(player, tprintf("%c/SAMP%c", TAG_START, TAG_END)); + notify_noenter(player, close_tag("SAMP")); } /** Lowercase a string if we've been asked to */ @@ -1646,17 +1690,19 @@ show_compile_options(dbref player) #if (COMPRESSION_TYPE == 4) notify(player, T(" Attributes are 8-bit word compressed in memory.")); #endif - -#ifdef HAS_OPENSSL +#ifdef HAVE_SSL notify(player, T(" The MUSH was compiled with SSL support.")); #endif -#ifdef HAS_MYSQL - notify(player, T(" The MUSH was compiled with SQL support.")); -#endif -#ifdef HAS_MYSQL +#ifdef HAVE_MYSQL notify(player, T(" The MUSH was compiled with MySQL support.")); #endif +#ifdef HAVE_POSTGRESQL + notify(player, T(" The MUSH was compiled with Postgresql support.")); +#endif +#ifdef HAVE_SQLITE3 + notify(player, T(" The MUSH was compiled with Sqlite3 support.")); +#endif #ifdef INFO_SLAVE notify(player, T(" DNS and ident lookups are handled by a slave process.")); @@ -1664,7 +1710,6 @@ show_compile_options(dbref player) notify(player, T(" DNS and ident lookups are handled by the MUSH process.")); #endif - notify(player, T(" BSD sockets networking in use.")); notify(player, T(" Floating point functions are enabled.")); @@ -1707,4 +1752,10 @@ show_compile_options(dbref player) notify(player, T(" CPU usage limiting is NOT supported.")); #endif +#ifdef HAVE_INOTIFY + notify(player, T(" Changed help files will be automatically reindexed.")); +#endif + + + } diff --git a/src/cque.c b/src/cque.c index a64956e..766e983 100644 --- a/src/cque.c +++ b/src/cque.c @@ -14,11 +14,18 @@ #include #include #include +#include #ifdef I_SYS_TIME #include +#ifdef TIME_WITH_SYS_TIME +#include +#endif #else #include #endif +#ifdef HAVE_STDINT_H +#include +#endif #include "conf.h" #include "boolexp.h" @@ -34,6 +41,7 @@ #include "flags.h" #include "dbdefs.h" #include "log.h" +#include "intmap.h" #include "confmagic.h" @@ -42,9 +50,6 @@ extern dbref global_parent_depth[1]; EVAL_CONTEXT global_eval_context; -enum qid_flags qid_table[MAX_QID]; /**< List of flagged qids. */ -int qid_cnt; /**< What QID we're at */ - /** A queue entry. * This structure reprsents a queue entry on a linked list of queue * entries (a queue). It is used for all of the queues. @@ -58,42 +63,48 @@ typedef struct bque { dbref ooref; /**< Used when doing twin checks */ dbref sem; /**< semaphore object to block on */ char *semattr; /**< semaphore attribute to block on */ - time_t left; /**< seconds left until execution */ + time_t left; /**< seconds left until execution */ char *env[10]; /**< environment, from wild match */ char *rval[NUMQ]; /**< environment, from setq() */ char *comm; /**< command to be executed */ -#ifdef _SWMP_ - int sql_env[2]; /**< sql environment 0- Query ID, 1-Auth ID */ -#endif + uint32_t qid; /**< queue identification # */ char fqueued; /**< function inserted into queue */ - enum qid_flags qid; /**< queue identification # */ + enum qid_flags qstate; /**< queue current state */ HASHTAB namedregs; } BQUE; +slab *bque_slab = NULL; /**< slab for 'struct bque' allocations */ + +intmap *queue_map = NULL; +static uint32_t top_qid = 1; +#define MAX_PID (1U << 15) + static BQUE *qfirst = NULL, *qlast = NULL, *qwait = NULL; static BQUE *qlfirst = NULL, *qllast = NULL; static BQUE *qsemfirst = NULL, *qsemlast = NULL; -static int add_to_generic(dbref player, int am, const char *name, int flags); +static int add_to_generic(dbref player, int am, const char *name, + uint32_t flags); static int add_to(dbref player, int am); static int add_to_sem(dbref player, int am, const char *name); static int queue_limit(dbref player); -void free_qentry(BQUE *point); +void free_qentry(BQUE * point); static int pay_queue(dbref player, const char *command); int wait_que(dbref player, int waituntil, char *command, - dbref cause, dbref sem, const char *semattr, int until, char finvoc); + dbref cause, dbref sem, const char *semattr, int until, + char finvoc); void init_qids(); -int create_qid(); int que_next(void); static void show_queue(dbref player, dbref victim, int q_type, - int q_quiet, int q_all, BQUE *q_ptr, int *tot, int *self, - int *del); -static void check_qsigs(BQUE **qchk); + int q_quiet, int q_all, BQUE * q_ptr, int *tot, + int *self, int *del); +static void check_qsigs(BQUE ** qchk); static void do_raw_restart(dbref victim); static int waitable_attr(dbref thing, const char *atr); -static void shutdown_a_queue(BQUE **head, BQUE **tail); - +static void shutdown_a_queue(BQUE ** head, BQUE ** tail); +static uint32_t create_qid(void); +static int do_haltqid(dbref player, uint32_t qid); extern sig_atomic_t cpu_time_limit_hit; /**< Have we used too much CPU? */ /** Attribute flags to be set or checked on attributes to be used @@ -101,31 +112,15 @@ extern sig_atomic_t cpu_time_limit_hit; /**< Have we used too much CPU? */ */ #define SEMAPHORE_FLAGS (AF_LOCKED | AF_PRIVATE | AF_NOCOPY | AF_NODUMP) - -void init_qids() { - int i; - - /* set whole thing to NULL */ - for(i = 0; i < MAX_QID; i++) - qid_table[i] = QID_FALSE; - qid_table[MAX_QID] = '\0'; - qid_cnt = 0; -} - -int create_qid() { /* find an unused QID */ - int i; - - for(i = 0; i < MAX_QID; i++) - if(qid_table[i] == QID_FALSE) - break; - /* No Good QID */ - if(qid_table[i] != QID_FALSE || i == MAX_QID) - return -1; - if(i > qid_cnt) /* set this so we don't go too high looking for a qid */ - qid_cnt = i; - /* flag the QID entry & return it */ - qid_table[i] = QID_ACTIVE; - return i; +/** Queue initializtion function. Must be called before anything + * is added to the queue. + */ +void +init_queue(void) +{ + bque_slab = slab_create("command queues", sizeof(BQUE)); + slab_set_opt(bque_slab, SLAB_ALLOC_BEST_FIT, 1); + queue_map = im_new(); } /* Returns true if the attribute on thing can be used as a semaphore. @@ -158,7 +153,7 @@ waitable_attr(dbref thing, const char *atr) } static int -add_to_generic(dbref player, int am, const char *name, int flags) +add_to_generic(dbref player, int am, const char *name, uint32_t flags) { int num = 0; ATTR *a; @@ -171,18 +166,18 @@ add_to_generic(dbref player, int am, const char *name, int flags) * it later, because clearing it may fail (perhaps someone's also * foolishly using it as a branch in an attribute tree) */ - sprintf(buff, "%d", num); - (void) atr_add(player, name, buff, GOD, flags); + snprintf(buff, sizeof buff, "%d", num); + (void) atr_add(player, name, buff, GOD, flags); if (!num) { (void) atr_clr(player, name, GOD); } - return (num); + return num; } static int add_to(dbref player, int am) { - return (add_to_generic(player, am, "QUEUE", 0)); + return (add_to_generic(player, am, "QUEUE", NOTHING)); } static int @@ -210,38 +205,23 @@ queue_limit(dbref player) * \param point queue entry to free. */ void -free_qentry(BQUE *point) +free_qentry(BQUE * point) { int a; - -#ifdef _SWMP_ - sqenv_clear(sql_env[0]); -#endif - /* first free up the QID */ - qid_table[point->qid] = QID_FALSE; - if(point->qid == qid_cnt) { - for(a = qid_cnt; a > -1; a--) - if(qid_table[a] != QID_FALSE) - break; - if(qid_table[a] != QID_FALSE) - qid_cnt = a; - else /* nothing on the queue at all.. set us down to 0 */ - qid_cnt = 0; - } for (a = 0; a < 10; a++) if (point->env[a]) { - mush_free((Malloc_t) point->env[a], "bqueue_env"); + mush_free(point->env[a], "bqueue_env"); } for (a = 0; a < NUMQ; a++) if (point->rval[a]) { - mush_free((Malloc_t) point->rval[a], "bqueue_rval"); + mush_free(point->rval[a], "bqueue_rval"); } - free_namedregs(&point->namedregs); if (point->semattr) - mush_free((Malloc_t) point->semattr, "bqueue_semattr"); + mush_free(point->semattr, "bqueue_semattr"); if (point->comm) - mush_free((Malloc_t) point->comm, "bqueue_comm"); - mush_free((Malloc_t) point, "BQUE"); + mush_free(point->comm, "bqueue_comm"); + im_delete(queue_map, point->qid); + slab_free(bque_slab, point); } static int @@ -249,13 +229,15 @@ pay_queue(dbref player, const char *command) { int estcost; estcost = - QUEUE_COST + - (QUEUE_LOSS ? ((get_random_long(0, QUEUE_LOSS - 1) == 0) ? 1 : 0) : 0); + QUEUE_COST + + (QUEUE_LOSS ? ((get_random_long(0, QUEUE_LOSS - 1) == 0) ? 1 : 0) : + 0); if (!quiet_payfor(player, estcost)) { notify(Owner(player), T("Not enough money to queue command.")); return 0; } - if (!NoPay(player) && (estcost != QUEUE_COST) && Track_Money(Owner(player))) { + if (!NoPay(player) && (estcost != QUEUE_COST) + && Track_Money(Owner(player))) { char *preserve_wnxt[10]; char *preserve_rnxt[NUMQ]; char *val_wnxt[10]; @@ -263,8 +245,8 @@ pay_queue(dbref player, const char *command) char *preserves[10]; char *preserveq[NUMQ]; HASHTAB preserve_namedregs; - save_global_nxt("pay_queue_save", preserve_wnxt, preserve_rnxt, val_wnxt, - val_rnxt); + save_global_nxt("pay_queue_save", preserve_wnxt, preserve_rnxt, + val_wnxt, val_rnxt); save_global_regs("pay_queue_save", preserveq); save_global_env("pay_queue_save", preserves); init_namedregs(&preserve_namedregs); @@ -277,8 +259,8 @@ pay_queue(dbref player, const char *command) free_namedregs(&preserve_namedregs); restore_global_regs("pay_queue_save", preserveq); restore_global_env("pay_queue_save", preserves); - restore_global_nxt("pay_queue_save", preserve_wnxt, preserve_rnxt, val_wnxt, - val_rnxt); + restore_global_nxt("pay_queue_save", preserve_wnxt, preserve_rnxt, + val_wnxt, val_rnxt); } if (queue_limit(QUEUE_PER_OWNER ? Owner(player) : player)) { notify_format(Owner(player), @@ -297,6 +279,36 @@ pay_queue(dbref player, const char *command) return 1; } +/* Create a Queue ID + * Return > 0 Good Qid. + * Return -1 Can not create Qid. + */ + +static uint32_t +create_qid(void) +{ + uint32_t qid = top_qid; + + if (im_count(queue_map) >= (int) MAX_PID) { + do_rawlog(LT_ERR, + T + ("There are %ld queue entries! That's too many. Failing to add another."), + (long) im_count(queue_map)); + return -1; + } + + while (1) { + if (qid > MAX_QID) + qid = 1; + if (im_exists(queue_map, qid)) + qid++; + else { + top_qid = qid + 1; + return qid; + } + } +} + /** Add a new entry onto the player or object command queues. * This function adds a new entry to the back of the player or * object command queues (depending on whether the call was @@ -312,13 +324,17 @@ parse_que(dbref player, const char *command, dbref cause) int a; BQUE *tmp; int qid; + if (!IsPlayer(player) && (Halted(player))) return; if (!pay_queue(player, command)) /* make sure player can afford to do it */ return; - if((qid = create_qid()) == -1) /* No room for a process ID, don't do anything */ - return; - tmp = (BQUE *) mush_malloc(sizeof(BQUE), "BQUE"); + if ((qid = create_qid()) == -1) { + /* No room for another queue ID, give up & return fail message. */ + notify(player, T("Queue entry table full. Try again later.")); + return; + } + tmp = (BQUE *) slab_malloc(bque_slab, NULL); tmp->qid = qid; tmp->comm = mush_strdup(command, "bqueue_comm"); tmp->semattr = NULL; @@ -329,10 +345,6 @@ parse_que(dbref player, const char *command, dbref cause) tmp->realcause = tmp->cause = cause; tmp->fqueued = 0; tmp->ooref = options.twinchecks ? ooref : NOTHING; -#ifdef _SWMP_ - tmp->sql_env[0] = sql_env[0]; - tmp->sql_env[1] = sql_env[1]; -#endif for (a = 0; a < 10; a++) if (!global_eval_context.wnxt[a]) tmp->env[a] = NULL; @@ -343,7 +355,8 @@ parse_que(dbref player, const char *command, dbref cause) if (!global_eval_context.rnxt[a] || !global_eval_context.rnxt[a][0]) tmp->rval[a] = NULL; else { - tmp->rval[a] = mush_strdup(global_eval_context.rnxt[a], "bqueue_rval"); + tmp->rval[a] = + mush_strdup(global_eval_context.rnxt[a], "bqueue_rval"); } init_namedregs(&tmp->namedregs); copy_namedregs(&tmp->namedregs, &global_eval_context.namedregs); @@ -364,16 +377,17 @@ parse_que(dbref player, const char *command, dbref cause) } void -div_parse_que(dbref division, const char *command, dbref called_division, dbref player) +div_parse_que(dbref division, const char *command, dbref called_division, + dbref player) { int a, qid; BQUE *tmp; if (!IsPlayer(division) && (Halted(division))) return; - if((qid = create_qid()) == -1) /* No room to process shit.. don't do shit */ - return; - tmp = (BQUE *) mush_malloc(sizeof(BQUE), "BQUE"); + if ((qid = create_qid()) == -1) /* No room to process shit.. don't do shit */ + return; + tmp = (BQUE *) slab_malloc(bque_slab, NULL); tmp->qid = qid; tmp->comm = mush_strdup(command, "bqueue_comm"); tmp->semattr = NULL; @@ -395,7 +409,8 @@ div_parse_que(dbref division, const char *command, dbref called_division, dbref if (!global_eval_context.rnxt[a] || !global_eval_context.rnxt[a][0]) tmp->rval[a] = NULL; else { - tmp->rval[a] = mush_strdup(global_eval_context.rnxt[a], "bqueue_rval"); + tmp->rval[a] = + mush_strdup(global_eval_context.rnxt[a], "bqueue_rval"); } init_namedregs(&tmp->namedregs); copy_namedregs(&tmp->namedregs, &global_eval_context.namedregs); @@ -412,6 +427,7 @@ div_parse_que(dbref division, const char *command, dbref called_division, dbref } else qllast = qlfirst = tmp; } + im_insert(queue_map, tmp->qid, tmp); } @@ -447,12 +463,12 @@ queue_attribute_getatr(dbref executor, const char *atrname, int noparent) } int -queue_attribute_useatr(dbref executor, ATTR *a, dbref enactor) +queue_attribute_useatr(dbref executor, ATTR * a, dbref enactor) { char *start, *command; dbref powinherit = NOTHING; dbref local_ooref; - if(AL_FLAGS(a) & AF_POWINHERIT) + if (AL_FLAGS(a) & AF_POWINHERIT) powinherit = atr_on_obj; start = safe_atr_value(a); command = start; @@ -469,11 +485,15 @@ queue_attribute_useatr(dbref executor, ATTR *a, dbref enactor) command++; } local_ooref = ooref; - if(options.twinchecks && ( ((global_parent_depth[0] < 1 && global_parent_depth[1] != executor) || - global_parent_depth[1] != NOTHING) && - !has_flag_by_name(global_parent_depth[1], "AUTH_PARENT", NOTYPE) )) ooref = AL_CREATOR(a); + if (options.twinchecks + && + (((global_parent_depth[0] < 1 && global_parent_depth[1] != executor) + || global_parent_depth[1] != NOTHING) + && !has_flag_by_name(global_parent_depth[1], "AUTH_PARENT", + NOTYPE))) + ooref = AL_CREATOR(a); /* Now we're going to do a little magick... If we caught powinhearit isn't nothing we're using div_parse_que instead */ - if(GoodObject(powinherit)) + if (GoodObject(powinherit)) div_parse_que(powinherit, command, executor, enactor); else parse_que(executor, command, enactor); @@ -511,9 +531,9 @@ wait_que(dbref player, int waittill, char *command, dbref cause, dbref sem, } if (!pay_queue(player, command)) /* make sure player can afford to do it */ return -1; - if((qid = create_qid()) < 0) /* can't obtain a QID */ - return -1; - tmp = (BQUE *) mush_malloc(sizeof(BQUE), "BQUE"); + if ((qid = create_qid()) == -1) /* can not obtain a QID */ + return -1; + tmp = (BQUE *) slab_malloc(bque_slab, NULL); tmp->qid = qid; tmp->comm = mush_strdup(command, "bqueue_comm"); tmp->player = player; @@ -521,12 +541,8 @@ wait_que(dbref player, int waittill, char *command, dbref cause, dbref sem, tmp->realcause = tmp->cause = cause; tmp->semattr = NULL; tmp->next = NULL; - tmp->ooref = ooref; /* catch state ooref */ + tmp->ooref = ooref; /* catch state ooref */ tmp->fqueued = finvoc; -#ifdef _SWMP_ - tmp->sql_env[0] = sql_env[0]; - tmp->sql_env[1] = sql_env[1]; -#endif for (a = 0; a < 10; a++) { if (!global_eval_context.wnxt[a]) tmp->env[a] = NULL; @@ -538,14 +554,15 @@ wait_que(dbref player, int waittill, char *command, dbref cause, dbref sem, if (!global_eval_context.rnxt[a] || !global_eval_context.rnxt[a][0]) tmp->rval[a] = NULL; else { - tmp->rval[a] = mush_strdup(global_eval_context.rnxt[a], "bqueue_rval"); + tmp->rval[a] = + mush_strdup(global_eval_context.rnxt[a], "bqueue_rval"); } } init_namedregs(&tmp->namedregs); copy_namedregs(&tmp->namedregs, &global_eval_context.namedregs); if (until) { - tmp->left = waittill; + tmp->left = (time_t) waittill; } else { if (waittill >= 0) tmp->left = mudtime + waittill; @@ -570,7 +587,7 @@ wait_que(dbref player, int waittill, char *command, dbref cause, dbref sem, /* Put it on the end of the semaphore queue */ tmp->semattr = - mush_strdup(semattr ? semattr : "SEMAPHORE", "bqueue_semattr"); + mush_strdup(semattr ? semattr : "SEMAPHORE", "bqueue_semattr"); if (qsemlast != NULL) { qsemlast->next = tmp; qsemlast = tmp; @@ -578,6 +595,7 @@ wait_que(dbref player, int waittill, char *command, dbref cause, dbref sem, qsemfirst = qsemlast = tmp; } } + im_insert(queue_map, tmp->qid, tmp); return qid; } @@ -700,7 +718,8 @@ do_top(int ncom) giveto(global_eval_context.cplr, QUEUE_COST); add_to(entry->queued, -1); entry->player = 0; - if (IsPlayer(global_eval_context.cplr) || !Halted(global_eval_context.cplr)) { + if (IsPlayer(global_eval_context.cplr) + || !Halted(global_eval_context.cplr)) { for (a = 0; a < 10; a++) global_eval_context.wenv[a] = entry->env[a]; for (a = 0; a < NUMQ; a++) { @@ -720,35 +739,39 @@ do_top(int ncom) r = global_eval_context.ccom; local_ooref = ooref; ooref = entry->ooref; - if(!entry->fqueued) { - process_expression(global_eval_context.ccom, &r, &s, - global_eval_context.cplr, entry->cause, - entry->realcause, PE_NOTHING, PT_SEMI, NULL); + if (!entry->fqueued) { + process_expression(global_eval_context.ccom, &r, &s, + global_eval_context.cplr, entry->cause, + entry->realcause, PE_NOTHING, PT_SEMI, + NULL); *r = '\0'; if (*s == ';') s++; - strcpy(tbuf, global_eval_context.ccom); - process_command(global_eval_context.cplr, tbuf, entry->cause, entry->realcause, 0); - if(global_eval_context.break_called) { - global_eval_context.break_called = 0; - s = global_eval_context.break_replace; - if(!*global_eval_context.break_replace) { - ooref = local_ooref; - break; - } - break_count--; - if(!break_count) { - notify(global_eval_context.cplr, T("@break recursion exceeded.")); - ooref = local_ooref; - break; - } - } + strcpy(tbuf, global_eval_context.ccom); + process_command(global_eval_context.cplr, tbuf, entry->cause, + entry->realcause, 0); + if (global_eval_context.break_called) { + global_eval_context.break_called = 0; + s = global_eval_context.break_replace; + if (!*global_eval_context.break_replace) { + ooref = local_ooref; + break; + } + break_count--; + if (!break_count) { + notify(global_eval_context.cplr, + T("@break recursion exceeded.")); + ooref = local_ooref; + break; + } + } } else { - process_expression(global_eval_context.ccom, &r, &s, - global_eval_context.cplr, entry->cause, entry->realcause, PE_DEFAULT, - PT_DEFAULT, (PE_Info *) NULL); - *r = '\0'; - notify(global_eval_context.cplr, global_eval_context.ccom); + process_expression(global_eval_context.ccom, &r, &s, + global_eval_context.cplr, entry->cause, + entry->realcause, PE_DEFAULT, PT_DEFAULT, + (PE_Info *) NULL); + *r = '\0'; + notify(global_eval_context.cplr, global_eval_context.ccom); } ooref = local_ooref; } @@ -817,7 +840,7 @@ que_next(void) static int drain_helper(dbref player __attribute__ ((__unused__)), dbref thing, dbref parent __attribute__ ((__unused__)), - char const *pattern __attribute__ ((__unused__)), ATTR *atr, + char const *pattern __attribute__ ((__unused__)), ATTR * atr, void *args __attribute__ ((__unused__))) { if (waitable_attr(thing, AL_NAME(atr))) @@ -905,7 +928,8 @@ dequeue_semaphores(dbref thing, char const *aname, int count, int all, add_to_sem(thing, -count, aname); } -COMMAND (cmd_notify_drain) { +COMMAND(cmd_notify_drain) +{ int drain; char *pos; char const *aname; @@ -918,7 +942,8 @@ COMMAND (cmd_notify_drain) { /* Make sure they gave an object ref */ if (!arg_left || !*arg_left) { - notify(player, T("You must specify an object to use for the semaphore.")); + notify(player, + T("You must specify an object to use for the semaphore.")); return; } @@ -960,7 +985,8 @@ COMMAND (cmd_notify_drain) { if (arg_right && *arg_right) { if (all) { notify(player, - T("You may not specify a semaphore count with the ALL switch.")); + T + ("You may not specify a semaphore count with the ALL switch.")); return; } if (!is_uinteger(arg_right)) { @@ -998,7 +1024,8 @@ COMMAND (cmd_notify_drain) { * returns qid */ int -do_wait(dbref player, dbref cause, char *arg1, char *cmd, int until, char finvoc) +do_wait(dbref player, dbref cause, char *arg1, char *cmd, bool until, + char finvoc) { dbref thing; char *tcount = NULL, *aname = NULL; @@ -1011,12 +1038,15 @@ do_wait(dbref player, dbref cause, char *arg1, char *cmd, int until, char finvoc global_eval_context.wnxt[j] = global_eval_context.wenv[j]; for (j = 0; j < NUMQ; j++) global_eval_context.rnxt[j] = global_eval_context.renv[j]; - copy_namedregs(&global_eval_context.namedregsnxt, &global_eval_context.namedregs); + copy_namedregs(&global_eval_context.namedregsnxt, + &global_eval_context.namedregs); arg2 = strip_braces(cmd); if (is_strict_integer(arg1)) { /* normal wait */ - qid = wait_que(player, parse_integer(arg1), arg2, cause, NOTHING, NULL, until, finvoc); + qid = + wait_que(player, parse_integer(arg1), arg2, cause, NOTHING, NULL, + until, finvoc); mush_free(arg2, "strip_braces.buff"); return qid; } @@ -1027,7 +1057,8 @@ do_wait(dbref player, dbref cause, char *arg1, char *cmd, int until, char finvoc if (aname) *aname++ = '\0'; if ((thing = - noisy_match_result(player, arg1, NOTYPE, MAT_EVERYTHING)) == NOTHING) { + noisy_match_result(player, arg1, NOTYPE, + MAT_EVERYTHING)) == NOTHING) { mush_free(arg2, "strip_braces.buff"); return -1; } @@ -1075,14 +1106,124 @@ do_wait(dbref player, dbref cause, char *arg1, char *cmd, int until, char finvoc thing = NOTHING; waitfor = -1; /* just in case there was a timeout given */ } - qid = wait_que(player, waitfor, arg2, cause, thing, aname, until, finvoc); + qid = + wait_que(player, waitfor, arg2, cause, thing, aname, until, finvoc); mush_free(arg2, "strip_braces.buff"); return qid; } +/** Interface to @wait/pid; modifies the wait times of queue + * entries. + * \param player the object doing the command. + * \param pidstr the process id to modify. + * \param timestr the new timeout. + * \param until true if timeout is an absolute time. + */ +void +do_waitpid(dbref player, const char *pidstr, const char *timestr, + bool until) +{ + uint32_t pid; + BQUE *q, *tmp, *last; + bool found; + + if (!is_uinteger(pidstr)) { + notify(player, T("That is not a valid qid!")); + return; + } + + pid = parse_uint32(pidstr, NULL, 10); + q = im_find(queue_map, pid); + + if (!q) { + notify(player, T("That is not a valid qid!")); + return; + } + + if (!controls(player, q->player) && !HaltAny(player)) { + notify(player, T("Permission denied.")); + return; + } + + if (q->sem != NOTHING && q->left == 0) { + notify(player, + T("You cannot adjust the timeout of an indefinite semaphore.")); + return; + } + + if (!is_strict_integer(timestr)) { + notify(player, T("That is not a valid timestamp.")); + return; + } + + if (until) { + int when; + + when = parse_integer(timestr); + + if (when < 0) + when = 0; + + q->left = (time_t) when; + + } else { + int offset = parse_integer(timestr); + + /* If timestr looks like +NNN or -NNN, add or subtract a number + of seconds to the current timeout. Otherwise, change timeout. + */ + if (timestr[0] == '+' || timestr[0] == '-') + q->left += offset; + else + q->left = mudtime + offset; + + if (q->left < 0) + q->left = 0; + } + + /* Now adjust it in the wait queue. Not a clever approach, but I + wrote it at 3 am and clever was not an option. */ + found = false; + for (tmp = qwait, last = NULL; tmp; last = tmp, tmp = tmp->next) { + if (tmp == q) { + if (last) + last->next = q->next; + else + qwait = qwait->next; + found = true; + break; + } + } + if (found) { + found = false; + for (tmp = qwait, last = NULL; tmp; last = tmp, tmp = tmp->next) { + if (tmp->left > q->left) { + if (last) { + last->next = q; + q->next = tmp; + } else { + q->next = qwait; + qwait = q; + } + found = true; + break; + } + } + if (!found) { + if (last) + last->next = q; + else + qwait = q; + q->next = NULL; + } + } + + notify_format(player, T("Queue entry with qid %u updated."), pid); +} + static void show_queue(dbref player, dbref victim, int q_type, int q_quiet, int q_all, - BQUE *q_ptr, int *tot, int *self, int *del) + BQUE * q_ptr, int *tot, int *self, int *del) { BQUE *tmp; for (tmp = q_ptr; tmp; tmp = tmp->next) { @@ -1091,29 +1232,36 @@ show_queue(dbref player, dbref victim, int q_type, int q_quiet, int q_all, (*del)++; else if (q_all || (Owner(tmp->player) == victim)) { if ((CanSeeQ(player, victim) - || Owns(tmp->player, player))) { - (*self)++; - if(q_quiet) - continue; + || Owns(tmp->player, player))) { + (*self)++; + if (q_quiet) + continue; switch (q_type) { - case 1: /* wait queue */ - notify_format(player, "[QID: %d%s/%ld]%s:%s", tmp->qid, qid_table[tmp->qid] == QID_FREEZE ? "(F)" : "", - tmp->left - mudtime, unparse_object(player, tmp->player), tmp->comm); + case 1: /* wait queue */ + notify_format(player, "[QID: %u%s/%ld]%s:%s", tmp->qid, + tmp->qstate == QID_FREEZE ? "(F)" : "", + tmp->left - mudtime, unparse_object(player, + tmp->player), + tmp->comm); break; - case 2: /* semaphore queue */ + case 2: /* semaphore queue */ if (tmp->left != 0) { - notify_format(player, "[QID: %d%s/#%d/%s/%ld]%s:%s", tmp->qid, qid_table[tmp->qid] == QID_FREEZE ? "(F)" : "", - tmp->sem, tmp->semattr, tmp->left - mudtime, + notify_format(player, "[QID: %u%s/#%d/%s/%ld]%s:%s", tmp->qid, + tmp->qstate == QID_FREEZE ? "(F)" : "", tmp->sem, + tmp->semattr, tmp->left - mudtime, unparse_object(player, tmp->player), tmp->comm); } else { - notify_format(player, "[QID: %d%s/#%d/%s]%s:%s", tmp->qid, qid_table[tmp->qid] == QID_FREEZE ? "(F)" : "", - tmp->sem, tmp->semattr, unparse_object(player, tmp->player), + notify_format(player, "[QID: %u%s/#%d/%s]%s:%s", tmp->qid, + tmp->qstate == QID_FREEZE ? "(F)" : "", tmp->sem, + tmp->semattr, unparse_object(player, + tmp->player), tmp->comm); } break; - default: /* player or object queue */ - notify_format(player, "[QID: %d%s] %s:%s", tmp->qid, qid_table[tmp->qid] == QID_FREEZE ? "(F)" : "", - unparse_object(player, tmp->player), tmp->comm); + default: /* player or object queue */ + notify_format(player, "[QID: %u%s] %s:%s", tmp->qid, + tmp->qstate == QID_FREEZE ? "(F)" : "", + unparse_object(player, tmp->player), tmp->comm); } } } @@ -1148,7 +1296,7 @@ do_queue(dbref player, const char *what, enum queue_type flag) else victim = match_result(player, what, TYPE_PLAYER, MAT_PLAYER | MAT_ABSOLUTE | MAT_ME); - } + } if (!CanSeeQ(player, victim)) victim = player; @@ -1183,172 +1331,119 @@ do_queue(dbref player, const char *what, enum queue_type flag) if (!quick) notify(player, T("------------ Queue Done ------------")); notify_format(player, - "Totals: Player...%d/%d[%ddel] Object...%d/%d[%ddel] Wait...%d/%d Semaphore...%d/%d", - pq, tpq, dpq, oq, toq, doq, wq, twq, sq, tsq); + T + ("Totals: Player...%d/%d[%ddel] Object...%d/%d[%ddel] Wait...%d/%d[%ddel] Semaphore...%d/%d"), + pq, tpq, dpq, oq, toq, doq, wq, twq, dwq, sq, tsq); } } -static void check_qsigs(BQUE **qchk) { - BQUE *next, *save, *trail, *point, *last; - char qid_chk_t[MAX_QID]; +static void +check_qsigs(BQUE ** qchk) +{ + BQUE *next, *save, *trail, *point, *last; + char qid_chk_t[top_qid + 1]; - memset(qid_chk_t, 0, MAX_QID); + memset(qid_chk_t, 0, top_qid + 1); - for(save = trail = point = *qchk; point != NULL;point = save) { - if(qid_table[point->qid] == QID_ACTIVE) { /* don't have to bother with these */ - trail = save; - save = point->next; - qid_chk_t[point->qid] = 1; - continue; - } else if(qid_chk_t[point->qid] == 1) { - trail = save; - save = point->next; - continue; - } - qid_chk_t[point->qid] = 1; - /* see what type of PID or on. */ - switch(qid_table[point->qid]) { /* Check for all possible re-sort signals */ - case QID_FREEZE: - point->left++; - break; - case QID_CONT: /* these we're just resorting, set to active */ - case QID_TIME: - qid_table[point->qid] = QID_ACTIVE; - break; - default: /* this doesn't happen */ - trail = save; - save = point->next; - continue; - } + for (save = trail = point = *qchk; point != NULL; point = save) { + if (point->qstate == QID_ACTIVE) { /* don't have to bother with these */ + trail = save; + save = point->next; + qid_chk_t[point->qid] = 1; + continue; + } else if (qid_chk_t[point->qid] == 1) { + trail = save; + save = point->next; + continue; + } + qid_chk_t[point->qid] = 1; + /* see what type of PID or on. */ + if (point->qstate == QID_FREEZE) + point->left++; - /* detach the process for a second */ - /* - last = save; - save = (trail->next = point->next); - trail = last; - */ + /* detach the process for a second */ - if(*qchk == point) { /* its the first one.. so adjust the next one to be the first one */ - *qchk = save = point->next; - } else { - trail->next = save = point->next; - trail = trail; - } - /* detach. */ - point->next = NULL; - /* retach it */ - for(last = NULL, next = *qchk; next != NULL && (next->left <= point->left); next = next->next) - last = next; - point->next = next; - if(last != NULL) - last->next = point; - else - *qchk = point; + if (*qchk == point) { /* its the first one.. so adjust the next one to be the first one */ + *qchk = save = point->next; + } else { + trail->next = save = point->next; + trail = trail; + } + /* detach. */ + point->next = NULL; + /* retach it */ + for (last = NULL, next = *qchk; + next != NULL && (next->left <= point->left); next = next->next) + last = next; + point->next = next; + if (last != NULL) + last->next = point; + else + *qchk = point; } } -/* find a queue by qid and return the queue struct of shit */ -/* qid - qid - * qproc - set process we're on - * qlist - set which queue list we're on - * return queue process we found - */ -BQUE *find_qid(int qid, BQUE **qlist, BQUE **qprev) { - BQUE *qproc; - - for(*qprev = qproc = qfirst; qproc; *qprev = qproc, qproc = qproc->next) - if(qproc->qid == qid) { - return qproc; - } - for(*qprev = qproc = qlfirst; qproc; *qprev = qproc, qproc = qproc->next) - if(qproc->qid == qid) { - return qproc; - } - for(*qprev = NULL, qproc = qwait; qproc; *qprev = qproc, qproc = qproc->next) - if(qproc->qid == qid) { - *qlist = qwait; - return qproc; - } - for(*qprev = NULL, qproc = qsemfirst; qproc; *qprev = qproc, qproc = qproc->next) - if(qproc->qid == qid) { - *qlist = qsemfirst; - return qproc; - } - - return NULL; -} +int +do_signal_qid(dbref signalby, uint32_t qid, enum qid_flags qflags, + int time) +{ + BQUE *qproc; + + /* Signal a QID with such & such signal */ + + /* First we'll check this so we don't duplicate abunch of code */ + if(qflags == QID_KILL) { + switch(do_haltqid(signalby, qid)) { + case 0: + return -1; + case -1: + return -3; + default: + return 1; + } + } else { + qproc = im_find(queue_map, qid); + if (!qproc || qproc->qid != qid) + return -1; + /* Check Signals */ + switch (qflags) { + case QID_FREEZE: + if (controls(signalby, qproc->player)) + qproc->qstate = QID_FREEZE; + else + return -3; + break; + case QID_CONT: + if (controls(signalby, qproc->player)) + qproc->qstate = QID_ACTIVE; + else + return -3; + break; + case QID_QUERY_T: + if (!controls(signalby, qproc->player)) + return -3; + if (qproc->left != 0) + return (qproc->left - mudtime); + else + return -3; + case QID_TIME: /* modify queue time */ + if (!controls(signalby, qproc->player)) + return -3; + if (time < 0) /* can't wait negative amount of time */ + return 0; + if (qproc->left == 0) /* We don't adjust time of regular queue thingies */ + return -2; + qproc->left = mudtime + time; + /* No need to change the state with this signal */ + break; + default: + return -2; /* Not a valid signal */ -int do_signal_qid(dbref signalby, int qid, enum qid_flags qflags, int time) { - BQUE *qproc, *qprev, *qsave; - - /* Signal a QID with such & such signal */ - - /* First Quick Check to make sure its a valid QID */ - if(qid > qid_cnt || qid >= MAX_QID || qid_table[qid] == QID_FALSE) - return -1; - qproc = find_qid(qid, &qsave, &qprev); - if(!qproc || qproc->qid != qid) - return -1; - /* Check Signals */ - switch(qflags) { - case QID_FREEZE: - if(controls(signalby, qproc->player)) - qid_table[qid] = QID_FREEZE; - else - return -3; - break; - case QID_CONT: - if(controls(signalby, qproc->player)) - qid_table[qid] = QID_ACTIVE; - else - return -3; - break; - case QID_QUERY_T: - if(!controls(signalby, qproc->player)) - return -3; - if(qsave == qwait || qsave == qsemfirst) { - return (qproc->left - mudtime); - } else return -3; - case QID_TIME: /* modify queue time */ - if(!controls(signalby, qproc->player)) - return -3; - if(time < 0) /* can't wait negative amount of time */ - return 0; - if(!qsave) /* We don't adjust time of regular queue thingies */ - return -2; - qproc->left = mudtime + time; - /* this will let it stay frozen if it is */ - if(qid_table[qid] == QID_ACTIVE) - qid_table[qid] = QID_TIME; - break; - case QID_KILL: - if(!controls(signalby, qproc->player) && !CanHalt(signalby, qproc->player)) - return -3; - add_to(QUEUE_PER_OWNER ? Owner(qproc->player) : qproc->player, -1); - giveto(Owner(qproc->player), QUEUE_COST); - if(!qsave) { /* This is all we have to do for these, isn't that great? */ - qproc->player = NOTHING; - } else { /* Wait queues or semas - * we have to kill 'em completely from this point */ - if(qprev) - qprev->next = qproc->next; - else { - if(qsave == qwait) - qwait = qproc->next; - else { - qsemfirst = qproc->next; - add_to_sem(qproc->sem, -1, qproc->semattr); - } - } - free_qentry(qproc); - } - break; - default: - return -2; /* Not a valid signal */ + } + } - } - return 1; + return 1; } @@ -1429,7 +1524,8 @@ do_halt(dbref owner, const char *ncom, dbref victim) global_eval_context.wnxt[j] = global_eval_context.wenv[j]; for (j = 0; j < NUMQ; j++) global_eval_context.rnxt[j] = global_eval_context.renv[j]; - copy_namedregs(&global_eval_context.namedregsnxt, &global_eval_context.namedregs); + copy_namedregs(&global_eval_context.namedregsnxt, + &global_eval_context.namedregs); parse_que(player, ncom, player); } } @@ -1458,7 +1554,8 @@ do_halt1(dbref player, const char *arg1, const char *arg2) return; } if (arg2 && *arg2 && !controls(player, victim)) { - notify(player, T("You may not use @halt obj=command on this object.")); + notify(player, + T("You may not use @halt obj=command on this object.")); return; } /* If victim's a player, we halt all of their objects */ @@ -1470,7 +1567,8 @@ do_halt1(dbref player, const char *arg1, const char *arg2) notify(player, T("All of your objects have been halted.")); } else { notify_format(player, - T("All objects for %s have been halted."), Name(victim)); + T("All objects for %s have been halted."), + Name(victim)); notify_format(victim, T("All of your objects have been halted by %s."), Name(player)); @@ -1478,9 +1576,9 @@ do_halt1(dbref player, const char *arg1, const char *arg2) } else { if (Owner(victim) != player) { notify_format(player, "%s: %s's %s(%s)", T("Halted"), - Name(Owner(victim)), Name(victim), unparse_dbref(victim)); - notify_format(Owner(victim), - "%s: %s(%s), by %s", T("Halted"), + Name(Owner(victim)), Name(victim), + unparse_dbref(victim)); + notify_format(Owner(victim), "%s: %s(%s), by %s", T("Halted"), Name(victim), unparse_dbref(victim), Name(player)); } if (*arg2 == '\0') @@ -1489,6 +1587,83 @@ do_halt1(dbref player, const char *arg1, const char *arg2) } } +/** Halt a particular Qid.. + * \param player the enactor. + * \param arg1 string representing the pid to halt. + * \return 0 for no such pid, -1 for perm denied, 1 for good + */ +int +do_haltqid(dbref player, uint32_t qid) +{ + BQUE *q; + dbref victim; + + q = im_find(queue_map, qid); + + if (!q) + return 0; + + victim = q->player; + if (!controls(player, victim) && !HaltAny(player)) + return -1; + + /* Instead of trying to track what queue this entry currently + belongs too, flag it as halted and just not execute it when its + turn comes up (Or show it in @ps, etc.). Exception is for + semaphores, which otherwise might wait forever. */ + q->player = NOTHING; + + if (q->semattr) { + BQUE *last = NULL, *tmp; + + for (tmp = qsemfirst; tmp; last = tmp, tmp = tmp->next) { + if (tmp == q) { + if (last) + last->next = tmp->next; + else + qsemfirst = tmp->next; + + if (qsemlast == tmp) + qsemlast = last; + + break; + } + } + + giveto(victim, QUEUE_COST); + add_to_sem(q->sem, -1, q->semattr); + free_qentry(q); + } + return 1; +} + +void +do_haltpid(dbref player, const char *arg1) +{ + uint32_t pid; + + if (!is_uinteger(arg1)) { + notify(player, T("That is not a valid pid!")); + return; + } + + pid = parse_uint32(arg1, NULL, 10); + + switch(do_haltqid(player, pid)) { + case 0: + notify(player, T("That is not a valid pid!")); + return; + case -1: + notify(player, T("Permission denied.")); + return; + default: + notify_format(player, T("Queue entry with pid %u halted."), pid); + return; + } +} + + + /** Halt all objects in the database. * \param player the enactor. */ @@ -1542,7 +1717,7 @@ do_allrestart(dbref player) static void do_raw_restart(victim) - dbref victim; +dbref victim; { dbref thing; @@ -1589,9 +1764,9 @@ do_restart_com(dbref player, const char *arg1) } else { notify_format(player, "Restarting: %s's %s(%s)", - Name(Owner(victim)), Name(victim), unparse_dbref(victim)); - notify_format(Owner(victim), - "Restarting: %s(%s), by %s", + Name(Owner(victim)), Name(victim), + unparse_dbref(victim)); + notify_format(Owner(victim), "Restarting: %s(%s), by %s", Name(victim), unparse_dbref(victim), Name(player)); } } else { @@ -1623,7 +1798,7 @@ shutdown_queues(void) static void -shutdown_a_queue(BQUE **head, BQUE **tail) +shutdown_a_queue(BQUE ** head, BQUE ** tail) { BQUE *entry; /* Drain out a queue */ @@ -1640,39 +1815,52 @@ shutdown_a_queue(BQUE **head, BQUE **tail) } } -void init_namedregs(HASHTAB *regs) { - hashinit(regs, 16, sizeof(char *)); +void +init_namedregs(HASHTAB * regs) +{ + hashinit(regs, 16); } -void free_namedregs(HASHTAB *regs) { +void +free_namedregs(HASHTAB * regs) +{ clear_namedregs(regs); - hashfree(regs); + /* FIXME: This crashes us on reboots */ + /* hashfree(regs); */ } -void clear_namedregs(HASHTAB *regs) { +void +clear_namedregs(HASHTAB * regs) +{ char *value; - for(value = (char *) hash_firstentry(regs); value; value = (char *) hash_nextentry(regs)) + for (value = (char *) hash_firstentry(regs); value; + value = (char *) hash_nextentry(regs)) mush_free(value, "namedreg"); - hashflush(regs, 16); + /* FIXME: This is crashign us for some reason.. */ + /* hashflush(regs, 16); */ } -void copy_namedregs(HASHTAB *dest, HASHTAB *src) { +void +copy_namedregs(HASHTAB * dest, HASHTAB * src) +{ char *key; - for(key = hash_firstentry(src); key; key = hash_nextentry_key(src)) + for (key = hash_firstentry(src); key; key = (char *) hash_nextentry_key(src)) set_namedreg(dest, key, get_namedreg(src, key)); } -void set_namedreg(HASHTAB *regs, const char *name, const char *value) { +void +set_namedreg(HASHTAB * regs, const char *name, const char *value) +{ char *key; char *oldvalue; key = strupper(name); oldvalue = (char *) hashfind(key, regs); - if(oldvalue) { + if (oldvalue) { mush_free(oldvalue, "namedreg"); hashdelete(key, regs); } @@ -1680,7 +1868,9 @@ void set_namedreg(HASHTAB *regs, const char *name, const char *value) { hashadd(key, mush_strdup(value, "namedreg"), regs); } -const char *get_namedreg(HASHTAB *regs, const char *name) { +const char * +get_namedreg(HASHTAB * regs, const char *name) +{ char *key; char *value; @@ -1688,25 +1878,27 @@ const char *get_namedreg(HASHTAB *regs, const char *name) { value = (char *) hashfind(key, regs); - if(value) + if (value) return value; return ""; } -FUNCTION(fun_wait) { - char tbuf[BUFFER_LEN], *tbp; - const char *p; - - if(!args[0] || !*args[0] || !args[1] || !*args[1]) - safe_str("#-1", buff, bp); - else if(!command_check_byname(executor, "@wait")) - safe_str("#-1 PERMISSION DENIED", buff, bp); - else { - tbp = tbuf; - p = args[0]; - process_expression(tbuf, &tbp, &p, executor, caller, enactor, PE_DEFAULT, PT_DEFAULT, pe_info); - *tbp = '\0'; - safe_integer(do_wait(executor, caller, tbuf, args[1], 0, 1), buff, bp); - } +FUNCTION(fun_wait) +{ + char tbuf[BUFFER_LEN], *tbp; + const char *p; + + if (!args[0] || !*args[0] || !args[1] || !*args[1]) + safe_str("#-1", buff, bp); + else if (!command_check_byname(executor, "@wait")) + safe_str("#-1 PERMISSION DENIED", buff, bp); + else { + tbp = tbuf; + p = args[0]; + process_expression(tbuf, &tbp, &p, executor, caller, enactor, + PE_DEFAULT, PT_DEFAULT, pe_info); + *tbp = '\0'; + safe_integer(do_wait(executor, caller, tbuf, args[1], 0, 1), buff, bp); + } } diff --git a/src/create.c b/src/create.c index ad8dc65..234316b 100644 --- a/src/create.c +++ b/src/create.c @@ -15,7 +15,9 @@ #include "mushdb.h" #include "attrib.h" #include "match.h" +#ifdef CHAT_SYSTEM #include "extchat.h" +#endif #include "log.h" #include "flags.h" #include "dbdefs.h" @@ -52,7 +54,7 @@ parse_linkable_room(dbref player, const char *room_name) } else if (!strcasecmp(room_name, "home")) { return HOME; /* HOME is always linkable */ } else { - room = parse_dbref(room_name); + room = parse_objid(room_name); } /* check room */ @@ -508,7 +510,7 @@ do_create(dbref player, char *name, int cost) PUSH(thing, Contents(Source(player))); /* and we're done */ - notify_format(player, "Created: Object %s.", unparse_dbref(thing)); + notify_format(player, T("Created: Object %s."), unparse_dbref(thing)); current_state.things++; /* Replacement for local_data_create */ MODULE_ITER(m) @@ -535,6 +537,7 @@ clone_object(dbref player, dbref thing, const char *newname, int preserve) else set_name(clone, Name(thing)); s_Pennies(clone, Pennies(thing)); + AttrCount(clone) = 0; atr_cpy(clone, thing); Locks(clone) = NULL; clone_locks(player, thing, clone); diff --git a/src/cron.c b/src/cron.c index c7ba723..33edd1f 100644 --- a/src/cron.c +++ b/src/cron.c @@ -116,7 +116,7 @@ start_cron(void) enum SPEC_TYPE which; - hashinit(&crontab, 32, sizeof(cronjob)); + hashinit(&crontab, 32); /* Load Default CronTable */ for(i = 0; default_cron_table[i].name != NULL; i++) { @@ -126,11 +126,11 @@ start_cron(void) job->owner = default_cron_table[i].owner; job->object = default_cron_table[i].object; job->type = default_cron_table[i].type; - strcpy(job->name, default_cron_table[i].name); - strcpy(job->format, default_cron_table[i].format); - strcpy(job->attrib, default_cron_table[i].attribute); + mush_strncpy(job->name, default_cron_table[i].name, CRON_NAME_LEN); + mush_strncpy(job->format, default_cron_table[i].format, CRON_FORMAT_LEN); + mush_strncpy(job->attrib, default_cron_table[i].attribute, ATTRIBUTE_NAME_LIMIT); memset(tmp_format, '\0', BUFFER_LEN); - strcpy(tmp_format, job->format); + mush_strncpy(tmp_format, job->format, CRON_FORMAT_LEN); which = CS_MINUTE; fp_h = fp_t = tmp_format; diff --git a/src/csrimalloc.c b/src/csrimalloc.c index d214696..28e6775 100644 --- a/src/csrimalloc.c +++ b/src/csrimalloc.c @@ -134,18 +134,6 @@ extern int open proto((const char * /*path */ , int /*flags */ , ...)); #define caddr_t char * extern caddr_t sbrk proto((int)); -#ifdef _SC_PAGESIZE /* Solaris 2.x, SVR4? */ -#define getpagesize() sysconf(_SC_PAGESIZE) -#else /* ! _SC_PAGESIZE */ -#ifdef _SC_PAGE_SIZE /* HP, IBM */ -#define getpagesize() sysconf(_SC_PAGE_SIZE) -#else /* ! _SC_PAGE_SIZE */ -#ifndef getpagesize -extern int getpagesize proto((void)); -#endif /* getpagesize */ -#endif /* _SC_PAGE_SIZE */ -#endif /* _SC_PAGESIZE */ - #ifdef _AIX /* IBM AIX doesn't declare sbrk, but is STDHEADERS. */ extern caddr_t sbrk proto((int)); #endif @@ -187,7 +175,7 @@ extern caddr_t mmap proto((caddr_t, size_t, int, int, int, off_t)); #endif /* EXTERNS_H__ */ /* Do not add anything after this line */ -/* $Id: csrimalloc.c,v 1.2 2005-12-13 20:34:11 ari Exp $ */ +/* $Id: csrimalloc.c 1.23.1.8 Wed, 26 May 2004 09:52:42 -0500 dunemush $ */ #ifndef __ASSERT_H__ #define __ASSERT_H__ #ifdef CSRI_DEBUG @@ -219,7 +207,7 @@ proto((const char *, const char *, univptr_t, int, const char *, int)); #include #endif -/* $Id: csrimalloc.c,v 1.2 2005-12-13 20:34:11 ari Exp $ */ +/* $Id: csrimalloc.c 1.23.1.8 Wed, 26 May 2004 09:52:42 -0500 dunemush $ */ #ifndef __ALIGN_H__ #define __ALIGN_H__ /* @@ -670,7 +658,7 @@ typedef union word Word; * Remember to initialize the variable in globals.c if you want, and * provide an alternative short name in globrename.h */ -/* $Id: csrimalloc.c,v 1.2 2005-12-13 20:34:11 ari Exp $ */ +/* $Id: csrimalloc.c 1.23.1.8 Wed, 26 May 2004 09:52:42 -0500 dunemush $ */ #ifndef __GLOBALRENAME_H__ #define __GLOBALRENAME_H__ /* @@ -740,9 +728,11 @@ size_t _malloc_minchunk = FIXEDOVERHEAD; * improves performance considerably, sez Knuth */ Word *_malloc_rovers[MAXBINS + 1] = { NULL }; + const size_t _malloc_binmax[MAXBINS] = { 8, 16, 32, 64, 128, 256, 512, 1024 }; + int _malloc_firstbin = 0; int _malloc_lastbin = 0; Word *_malloc_hiword = NULL; @@ -785,7 +775,7 @@ int _malloc_scount[MAXPROFILESIZE]; int _malloc_debugging = 0; #endif /* CSRI_DEBUG */ -univptr_t (*_malloc_memfunc) proto((size_t)) = _mal_sbrk; +univptr_t(*_malloc_memfunc) proto((size_t)) = _mal_sbrk; #ifndef __GLOBALS_H__ #define __GLOBALS_H__ @@ -794,35 +784,42 @@ univptr_t (*_malloc_memfunc) proto((size_t)) = _mal_sbrk; * provide an alternative short name in globrename.h */ -extern -size_t _malloc_minchunk; + extern + size_t + _malloc_minchunk; -extern Word *_malloc_rovers[]; -extern const -size_t _malloc_binmax[]; -extern int - _malloc_firstbin; -extern int - _malloc_lastbin; -extern Word *_malloc_hiword; -extern Word *_malloc_loword; + extern Word * + _malloc_rovers[]; + extern const + size_t + _malloc_binmax[]; + extern int + _malloc_firstbin; + extern int + _malloc_lastbin; + extern Word * + _malloc_hiword; + extern Word * + _malloc_loword; -extern -size_t _malloc_sbrkunits; + extern + size_t + _malloc_sbrkunits; -extern Word *_malloc_mem; + extern Word * + _malloc_mem; -extern int - _malloc_tracing; /* No tracing */ -extern char - _malloc_statsbuf[]; + extern int + _malloc_tracing; /* No tracing */ + extern char + _malloc_statsbuf[]; -extern int - _malloc_leaktrace; + extern int + _malloc_leaktrace; #ifdef CSRI_PROFILESIZES -extern int - _malloc_scount[]; + extern int + _malloc_scount[]; #endif /* CSRI_PROFILESIZES */ #ifdef CSRI_DEBUG @@ -831,16 +828,17 @@ extern int * thorough. 2 means check the entire heap on every call to * malloc/free/realloc/memalign. (the rest call these) */ -extern int - _malloc_debugging; + extern int + _malloc_debugging; #endif /* CSRI_DEBUG */ -extern -univptr_t (*_malloc_memfunc) - proto((size_t)); + extern + univptr_t(*_malloc_memfunc) +proto((size_t)); -extern int -__m_prblock proto((univptr_t, int, FILE *)); + extern int + __m_prblock + proto((univptr_t, int, FILE *)); #endif /* __GLOBALS_H__ */ /* Do not add anything after this line */ @@ -858,40 +856,44 @@ __m_prblock proto((univptr_t, int, FILE *)); #ifndef SPTREE_H #define SPTREE_H -typedef struct _spblk { - struct _spblk *leftlink; - struct _spblk *rightlink; - struct _spblk *uplink; - - univptr_t - key; /* formerly time/timetyp */ - univptr_t - data; /* formerly aux/auxtype */ - univptr_t - datb; -} SPBLK; - -typedef struct { - SPBLK *root; /* root node */ - - /* Statistics, not strictly necessary, but handy for tuning */ - - int - lookups; /* number of splookup()s */ - int - lkpcmps; /* number of lookup comparisons */ - - int - enqs; /* number of spenq()s */ - int - enqcmps; /* compares in spenq */ - - int - splays; - int - splayloops; - -} SPTREE; + typedef struct _spblk { + struct _spblk * + leftlink; + struct _spblk * + rightlink; + struct _spblk * + uplink; + + univptr_t + key; /* formerly time/timetyp */ + univptr_t + data; /* formerly aux/auxtype */ + univptr_t + datb; + } SPBLK; + + typedef struct { + SPBLK * + root; /* root node */ + + /* Statistics, not strictly necessary, but handy for tuning */ + + int + lookups; /* number of splookup()s */ + int + lkpcmps; /* number of lookup comparisons */ + + int + enqs; /* number of spenq()s */ + int + enqcmps; /* compares in spenq */ + + int + splays; + int + splayloops; + + } SPTREE; #if defined(__STDC__) #define __proto(x) x @@ -901,19 +903,29 @@ typedef struct { /* sptree.c */ /* init tree */ -extern SPTREE *__spinit __proto((void)); + extern SPTREE * + __spinit + __proto((void)); /* find key in a tree */ -extern SPBLK *__splookup __proto((univptr_t, SPTREE *)); + extern SPBLK * + __splookup + __proto((univptr_t, SPTREE *)); /* enter an item, allocating or replacing */ -extern SPBLK *__spadd __proto((univptr_t, univptr_t, univptr_t, SPTREE *)); + extern SPBLK * + __spadd + __proto((univptr_t, univptr_t, univptr_t, SPTREE *)); /* scan forward through tree */ -extern void -__spscan __proto((void (*)__proto((SPBLK *)), SPBLK *, SPTREE *)); + extern void + __spscan + __proto((void (*)__proto((SPBLK *)), SPBLK *, SPTREE *)); /* return tree statistics */ -extern char *__spstats __proto((SPTREE *)); + extern char * + __spstats + __proto((SPTREE *)); /* delete node from tree */ -extern void -__spdelete __proto((SPBLK *, SPTREE *)); + extern void + __spdelete + __proto((SPBLK *, SPTREE *)); #undef __proto @@ -921,10 +933,12 @@ __spdelete __proto((SPBLK *, SPTREE *)); #ifndef __CSRI_TRACE_H__ #define __CSRI_TRACE_H__ -extern void -__m_install_record proto((univptr_t, const char *)); -extern void -__m_delete_record proto((univptr_t)); + extern void + __m_install_record + proto((univptr_t, const char *)); + extern void + __m_delete_record + proto((univptr_t)); #define RECORD_FILE_AND_LINE(addr, fname, linenum) \ if (_malloc_leaktrace) { \ @@ -946,82 +960,83 @@ __m_delete_record proto((univptr_t)); #ifdef CSRI_TRACE /* Tracing malloc definitions - helps find leaks */ univptr_t - trace__malloc(size_t nbytes, const char *fname, int linenum); +trace__malloc(size_t nbytes, const char *fname, int linenum); univptr_t - trace__calloc(size_t nelem, size_t elsize, const char *fname, int linenum); +trace__calloc(size_t nelem, size_t elsize, const char *fname, int linenum); univptr_t - trace__realloc(univptr_t cp, size_t nbytes, const char *fname, int linenum); +trace__realloc(univptr_t cp, size_t nbytes, const char *fname, int linenum); univptr_t - trace__valloc(size_t size, const char *fname, int linenum); +trace__valloc(size_t size, const char *fname, int linenum); univptr_t - trace__memalign(size_t alignment, size_t size, const char *fname, int linenum); + trace__memalign + (size_t alignment, size_t size, const char *fname, int linenum); univptr_t - trace__emalloc(size_t nbytes, const char *fname, int linenum); +trace__emalloc(size_t nbytes, const char *fname, int linenum); univptr_t - trace__ecalloc(size_t nelem, size_t sz, const char *fname, int linenum); +trace__ecalloc(size_t nelem, size_t sz, const char *fname, int linenum); univptr_t - trace__erealloc(univptr_t ptr, size_t nbytes, const char *fname, int linenum); -char *trace__strdup(const char *s, const char *fname, int linenum); -char *trace__strsave(const char *s, const char *fname, int linenum); -void - trace__free(univptr_t cp, const char *fname, int linenum); -void - trace__cfree(univptr_t cp, const char *fname, int linenum); +trace__erealloc(univptr_t ptr, size_t nbytes, const char *fname, int linenum); + char *trace__strdup(const char *s, const char *fname, int linenum); + char *trace__strsave(const char *s, const char *fname, int linenum); + void + trace__free(univptr_t cp, const char *fname, int linenum); + void + trace__cfree(univptr_t cp, const char *fname, int linenum); #else /* CSRI_TRACE */ univptr_t - malloc(size_t nbytes); +malloc(size_t nbytes); univptr_t - calloc(size_t nelem, size_t elsize); +calloc(size_t nelem, size_t elsize); univptr_t - realloc(univptr_t cp, size_t nbytes); +realloc(univptr_t cp, size_t nbytes); univptr_t - valloc(size_t size); +valloc(size_t size); univptr_t - memalign(size_t alignment, size_t size); +memalign(size_t alignment, size_t size); univptr_t - emalloc(size_t nbytes); +emalloc(size_t nbytes); univptr_t - ecalloc(size_t nelem, size_t sz); +ecalloc(size_t nelem, size_t sz); univptr_t - erealloc(univptr_t ptr, size_t nbytes); +erealloc(univptr_t ptr, size_t nbytes); Free_t - free(univptr_t cp); +free(univptr_t cp); Free_t - cfree(univptr_t cp); +cfree(univptr_t cp); #endif /* CSRI_TRACE */ -int - __m_botch - (const char *s1, const char *s2, univptr_t p, - int is_end_ptr, const char *filename, int linenumber); -void - __m_prnode(SPBLK * spblk); -void - mal_contents(FILE * fp); + int + __m_botch + (const char *s1, const char *s2, univptr_t p, + int is_end_ptr, const char *filename, int linenumber); + void + __m_prnode(SPBLK * spblk); + void + mal_contents(FILE * fp); #ifdef CSRI_DEBUG -void - mal_debug(int level); -int - mal_verify(int fullcheck); + void + mal_debug(int level); + int + mal_verify(int fullcheck); #endif -void - mal_dumpleaktrace(FILE * fp); -void - mal_heapdump(FILE * fp); -void - mal_leaktrace(int value); -void - mal_sbrkset(int n); -void - mal_slopset(int n); + void + mal_dumpleaktrace(FILE * fp); + void + mal_heapdump(FILE * fp); + void + mal_leaktrace(int value); + void + mal_sbrkset(int n); + void + mal_slopset(int n); #ifdef CSRI_PROFILESIZES -void - mal_statsdump(FILE * fp); + void + mal_statsdump(FILE * fp); #endif -void - mal_trace(int value); -void - mal_mmap(char *fname); + void + mal_trace(int value); + void + mal_mmap(char *fname); #ifdef CSRI_TRACE @@ -1365,7 +1380,7 @@ __m_prblock(p, is_end_ptr, fp) } if (!VALID_START_SIZE_FIELD(blk)) { sprintf(buf, " ** bad size field: tags = 0x%x, 0x%x\n", - (unsigned int) SIZEFIELD(blk), (unsigned int) SIZEFIELD(blkend)); + SIZEFIELD(blk), SIZEFIELD(blkend)); (void) fputs(buf, fp); return 0; } @@ -1565,7 +1580,7 @@ _mal_mmap(nbytes) if ((char *) p + nbytes > mmf.i_end) { errno = ENOMEM; - return (univptr_t) -1; + return (univptr_t) - 1; } mmf.i_alloced += nbytes; return p; @@ -1578,21 +1593,21 @@ _mal_mmap(nbytes) mmap_filename = getenv("CSRIMALLOC_MMAPFILE"); if (mmap_filename == NULL) { errno = ENOMEM; - return (univptr_t) -1; + return (univptr_t) - 1; } } mmf.i_fd = open(mmap_filename, O_RDWR, 0666); if (mmf.i_fd < 0 || fstat(mmf.i_fd, &stbuf) < 0) - return (univptr_t) -1; + return (univptr_t) - 1; if (stbuf.st_size < nbytes) { errno = ENOMEM; - return (univptr_t) -1; + return (univptr_t) - 1; } mmf.i_size = stbuf.st_size; mmf.i_data = mmap((caddr_t) 0, mmf.i_size, PROT_READ | PROT_WRITE, MAP_SHARED, mmf.i_fd, (off_t) 0); if (mmf.i_data == (caddr_t) - 1) - return (univptr_t) -1; + return (univptr_t) - 1; mmf.i_end = mmf.i_data + mmf.i_size; mmf.i_alloced = nbytes; /* Advise vm system of random access pattern */ @@ -1604,7 +1619,7 @@ univptr_t _mal_mmap(nbytes) size_t nbytes __attribute__ ((__unused__)); { - return (univptr_t) -1; + return (univptr_t) - 1; } #endif /* HAVE_MMAP */ @@ -1881,7 +1896,7 @@ grabhunk(nwords) sbrkwords = (size_t) (((nwords + EXCESS) / _malloc_sbrkunits + 1) * _malloc_sbrkunits); morecore = sbrkwords * sizeof(Word) + SBRKEXTRA; - if ((cp = (*_malloc_memfunc) (morecore)) == (univptr_t) -1) + if ((cp = (*_malloc_memfunc) (morecore)) == (univptr_t) - 1) return (0); /* * Should first GUARANTEE that what sbrk returns is aligned to diff --git a/src/db.c b/src/db.c index 23d5eb4..4114113 100644 --- a/src/db.c +++ b/src/db.c @@ -14,6 +14,9 @@ #include #ifdef I_SYS_TIME #include +#ifdef TIME_WITH_SYS_TIME +#include +#endif #else #include #endif @@ -35,7 +38,11 @@ #include "privtab.h" #include "htab.h" #include "extmail.h" +#ifdef CHAT_SYSTEM +#include "extchat.h" +#endif #include "confmagic.h" +#include "ansi.h" #include "modules.h" extern struct module_entry_t *module_list; @@ -460,7 +467,7 @@ db_read_this_labeled_string(FILE * f, const char *label, char **value) } } -/** Read an integer with a given label. +/** Read an int with a given label. * If the label read is different than the one being checked, the * database load will abort with an error. * \param f the file to read from. @@ -468,7 +475,7 @@ db_read_this_labeled_string(FILE * f, const char *label, char **value) * \param value pointer to update to the number that was read. */ void -db_read_this_labeled_number(FILE * f, const char *label, int *value) +db_read_this_labeled_int(FILE * f, const char *label, int *value) { char *readlabel; char *readvalue; @@ -485,20 +492,61 @@ db_read_this_labeled_number(FILE * f, const char *label, int *value) *value = parse_integer(readvalue); } -/** Read an integer and label. +/** Read an int and label. * \param f the file to read from. * \param label pointer to update to the address of a static * buffer containing the label that was read. * \param value pointer to update to the number that was read. */ void -db_read_labeled_number(FILE * f, char **label, int *value) +db_read_labeled_int(FILE * f, char **label, int *value) { char *readvalue; db_read_labeled_string(f, label, &readvalue); *value = parse_integer(readvalue); } +/** Read a uint32_t with a given label. + * If the label read is different than the one being checked, the + * database load will abort with an error. + * \param f the file to read from. + * \param label the label that should be read. + * \param value pointer to update to the number that was read. + */ +void +db_read_this_labeled_uint32(FILE * f, const char *label, uint32_t * value) +{ + char *readlabel; + char *readvalue; + + db_read_labeled_string(f, &readlabel, &readvalue); + + if (strcmp(readlabel, label)) { + do_rawlog(LT_ERR, + T("DB: error: Got label '%s', expected label '%s' at line %d"), + readlabel, label, dbline); + longjmp(db_err, 1); + } + + *value = parse_uint32(readvalue, NULL, 10); +} + +/** Read a uint32_t and label. + * \param f the file to read from. + * \param label pointer to update to the address of a static + * buffer containing the label that was read. + * \param value pointer to update to the number that was read. + */ +void +db_read_labeled_uint32(FILE * f, char **label, uint32_t * value) +{ + char *readvalue; + db_read_labeled_string(f, label, &readvalue); + *value = parse_uint32(readvalue, NULL, 10); +} + + + /** Read a time_t with a given label. * If the label read is different than the one being checked, the * database load will abort with an error. @@ -591,7 +639,7 @@ db_write_labeled_string(FILE * f, char const *label, char const *value) } void -db_write_labeled_number(FILE * f, char const *label, int value) +db_write_labeled_int(FILE * f, char const *label, int value) { OUTPUT(fprintf(f, "%s %d\n", label, value)); } @@ -629,12 +677,12 @@ putlocks(FILE * f, lock_list *l) int count = 0; for (ll = l; ll; ll = ll->next) count++; - db_write_labeled_number(f, "lockcount", count); + db_write_labeled_int(f, "lockcount", count); for (ll = l; ll; ll = ll->next) { db_write_labeled_string(f, " type", ll->type); db_write_labeled_dbref(f, " creator", L_CREATOR(ll)); db_write_labeled_string(f, " flags", lock_flags_long(ll)); - db_write_labeled_number(f, " derefs", chunk_derefs(L_KEY(ll))); + db_write_labeled_int(f, " derefs", chunk_derefs(L_KEY(ll))); putboolexp(f, ll->key); /* putboolexp adds a '\n', so we won't. */ } @@ -661,16 +709,16 @@ db_write_obj_basic(FILE * f, dbref i, struct object *o) db_write_labeled_dbref(f, "owner", o->owner); db_write_labeled_dbref(f, "zone", o->zone); db_write_labeled_dbref(f, "division_object", o->division.object); - db_write_labeled_number(f, "level", o->division.level); - db_write_labeled_number(f, "pennies", Pennies(i)); - db_write_labeled_number(f, "type", Typeof(i)); + db_write_labeled_int(f, "level", o->division.level); + db_write_labeled_int(f, "pennies", Pennies(i)); + db_write_labeled_int(f, "type", Typeof(i)); db_write_labeled_string(f, "powergroup", (const char *) powergroups_list_on(i, 0)); db_write_labeled_string(f, "powers", division_list_powerz(i, 0)); db_write_labeled_string(f, "flags", bits_to_string("FLAG", o->flags, GOD, NOTHING)); db_write_labeled_string(f, "warnings", unparse_warnings(o->warnings)); - db_write_labeled_number(f, "created", (int) o->creation_time); - db_write_labeled_number(f, "modified", (int) o->modification_time); + db_write_labeled_int(f, "created", (int) o->creation_time); + db_write_labeled_int(f, "modified", (int) o->modification_time); if(o->lastmod && *o->lastmod) db_write_labeled_string(f, "lastmod", o->lastmod); else @@ -701,7 +749,7 @@ db_write_object(FILE * f, dbref i) continue; count++; } - db_write_labeled_number(f, "attrcount", count); + db_write_labeled_int(f, "attrcount", count); for (list = o->list; list; list = AL_NEXT(list)) { if (AF_Nodump(list)) @@ -709,11 +757,11 @@ db_write_object(FILE * f, dbref i) db_write_labeled_string(f, " name", AL_NAME(list)); db_write_labeled_dbref(f, " owner", Owner(AL_CREATOR(list))); db_write_labeled_string(f, " flags", atrflag_to_string(AL_FLAGS(list))); - db_write_labeled_number(f, " derefs", AL_DEREFS(list)); + db_write_labeled_int(f, " derefs", AL_DEREFS(list)); db_write_labeled_string(f, " writelock", unparse_boolexp(GOD, AL_WLock(list), UB_DBREF)); - db_write_labeled_number(f, " derefs", chunk_derefs(AL_WLock(list))); + db_write_labeled_int(f, " derefs", chunk_derefs(AL_WLock(list))); db_write_labeled_string(f, " readlock", unparse_boolexp(GOD, AL_RLock(list), UB_DBREF)); - db_write_labeled_number(f, " derefs", chunk_derefs(AL_RLock(list))); + db_write_labeled_int(f, " derefs", chunk_derefs(AL_RLock(list))); db_write_labeled_time_t(f, " modtime", AL_MODTIME(list)); db_write_labeled_string(f, " value", atr_value(list)); } @@ -825,7 +873,6 @@ db_paranoid_write_object(FILE * f, dbref i, int flag) char *p; char lastp; dbref owner; - int flags; int fixmemdb = 0; int count = 0; int attrcount = 0; @@ -841,7 +888,7 @@ db_paranoid_write_object(FILE * f, dbref i, int flag) attrcount++; } - db_write_labeled_number(f, "attrcount", attrcount); + db_write_labeled_int(f, "attrcount", attrcount); for (list = o->list; list; list = next) { next = AL_NEXT(list); @@ -864,10 +911,10 @@ db_paranoid_write_object(FILE * f, dbref i, int flag) count = 0; do { name[BUFFER_LEN - 6] = '\0'; - sprintf(tbuf1, "%s%d", name, count); + snprintf(tbuf1, BUFFER_LEN, "%s%d", name, count); count++; } while (count < 10000 && atr_get_noparent(i, tbuf1)); - strcpy(name, tbuf1); + mush_strncpy(name, tbuf1, BUFFER_LEN); } do_rawlog(LT_CHECK, T(" * Bad attribute name on #%d. Changing name to %s.\n"), @@ -888,7 +935,7 @@ db_paranoid_write_object(FILE * f, dbref i, int flag) db_write_labeled_string(f, " name", name); db_write_labeled_dbref(f, " owner", owner); db_write_labeled_string(f, " flags", atrflag_to_string(AL_FLAGS(list))); - db_write_labeled_number(f, " derefs", AL_DEREFS(list)); + db_write_labeled_int(f, " derefs", AL_DEREFS(list)); /* now check the attribute */ strcpy(tbuf1, atr_value(list)); @@ -913,7 +960,7 @@ db_paranoid_write_object(FILE * f, dbref i, int flag) db_write_labeled_string(f, " value", tbuf1); if (flag && fixmemdb) { /* Fix the db in memory */ - flags = AL_FLAGS(list); + privbits flags = AL_FLAGS(list); atr_clr(i, AL_NAME(list), owner); (void) atr_add(i, name, tbuf1, owner, flags); list = atr_get_noparent(i, name); @@ -968,6 +1015,7 @@ db_paranoid_write(FILE * f, int flag) dbflag += DBF_NEW_FLAGS; dbflag += DBF_DIVISIONS; dbflag += DBF_LABELS; + dbflag += DBF_SPIFFY_AF_ANSI; do_rawlog(LT_CHECK, "PARANOID WRITE BEGINNING...\n"); @@ -1013,7 +1061,7 @@ getref(FILE * f) longjmp(db_err, 1); } dbline++; - return strtol(buf, NULL, 10); + return parse_integer(buf); } @@ -1025,7 +1073,7 @@ getref(FILE * f) * \param f file pointer to read from. * \return pointer to static buffer containing string read. */ -const char * +char * getstring_noalloc(FILE * f) { static char buf[BUFFER_LEN]; @@ -1106,7 +1154,7 @@ get_new_locks(dbref i, FILE * f, int c) { char *val, *key; dbref creator; - int flags; + privbits flags; char type[BUFFER_LEN]; boolexp b; int count = c, derefs = 0, found = 0; @@ -1134,10 +1182,10 @@ get_new_locks(dbref i, FILE * f, int c) db_read_this_labeled_dbref(f, "creator", &creator); db_read_this_labeled_string(f, "flags", &val); flags = string_to_privs(lock_privs, val, 0); - db_read_this_labeled_number(f, "derefs", &derefs); + db_read_this_labeled_int(f, "derefs", &derefs); } else { - db_read_this_labeled_number(f, "creator", &creator); - db_read_this_labeled_number(f, "flags", &flags); + db_read_this_labeled_int(f, "creator", &creator); + db_read_this_labeled_uint32(f, "flags", &flags); } /* boolexp */ db_read_this_labeled_string(f, "key", &key); @@ -1184,7 +1232,7 @@ getlocks(dbref i, FILE * f) /* getboolexp() would already have complained. */ return; } else { - add_lock_raw(Owner(i), i, buf, b, -1); + add_lock_raw(Owner(i), i, buf, b, LF_DEFAULT); } } ungetc(c, f); @@ -1271,9 +1319,12 @@ get_list(FILE * f, dbref i) int c; char *p, *q; char tbuf1[BUFFER_LEN + 150]; - int flags; + privbits flags; int count = 0; - unsigned char derefs; + uint8_t derefs; + ansi_string *as; + char tbuf2[BUFFER_LEN]; + char *tb2; List(i) = NULL; tbuf1[0] = '\0'; @@ -1297,7 +1348,7 @@ get_list(FILE * f, dbref i) return -1; } *q++ = '\0'; - flags = atoi(q); + flags = parse_uinteger(q); /* Remove obsolete AF_NUKED flag just in case */ flags &= ~AF_NUKED; if (!(indb_flags & DBF_AF_VISUAL)) { @@ -1310,14 +1361,24 @@ get_list(FILE * f, dbref i) present. */ q = strchr(q, '^'); if (q++) - derefs = atoi(q); + derefs = parse_uinteger(q); else derefs = 0; /* We add the attribute assuming that atoi(p) is an ok dbref * since we haven't loaded the whole db and can't really tell * if it is or not. We'll fix this up at the end of the load */ - atr_new_add(i, tbuf1, getstring_noalloc(f), atoi(p), flags, derefs, TRUE_BOOLEXP, TRUE_BOOLEXP, 0); + tb2 = getstring_noalloc(f); + if (strchr(tb2, TAG_START) || strchr(tb2, ESC_CHAR)) { + as = parse_ansi_string(tb2); + tb2 = tbuf2; + safe_ansi_string(as, 0, as->len, tbuf2, &tb2); + *(tb2) = '\0'; + tb2 = tbuf2; + free_ansi_string(as); + } + + atr_new_add(i, tbuf1, tb2, atoi(p), flags, derefs, TRUE_BOOLEXP, TRUE_BOOLEXP, 0); count++; /* Check removed for atoi(q) == 0 (which results in NOTHING for that * parameter, and thus no flags), since this eliminates 'visual' @@ -1365,9 +1426,10 @@ db_read_attrs(FILE * f, dbref i, int count) time_t modtime; dbref owner; int derefs = 0, lock_derefs = 0; - int flags; + privbits flags; char *tmp; int found = 0; + ansi_string *as; List(i) = NULL; @@ -1387,17 +1449,17 @@ db_read_attrs(FILE * f, dbref i, int count) db_read_this_labeled_dbref(f, "owner", &owner); db_read_this_labeled_string(f, "flags", &tmp); flags = string_to_privs(attr_privs_view, tmp, 0); - db_read_this_labeled_number(f, "derefs", &derefs); + db_read_this_labeled_int(f, "derefs", &derefs); if(HAS_COBRADBFLAG(indb_flags,DBF_NEW_ATR_LOCK)) { db_read_this_labeled_string(f, "writelock", &tmp); strcpy(l_key, tmp); - db_read_this_labeled_number(f, "derefs", &lock_derefs); + db_read_this_labeled_int(f, "derefs", &lock_derefs); w_lock = parse_boolexp_d(GOD, l_key, (char *) "ATTR", lock_derefs); db_read_this_labeled_string(f, "readlock", &tmp); strcpy(l_key, tmp); - db_read_this_labeled_number(f, "derefs", &lock_derefs); + db_read_this_labeled_int(f, "derefs", &lock_derefs); r_lock = parse_boolexp_d(GOD, l_key, (char *) "ATTR", lock_derefs); } else { @@ -1413,6 +1475,15 @@ db_read_attrs(FILE * f, dbref i, int count) db_read_this_labeled_string(f, "value", &tmp); strcpy(value, tmp); + if (!(globals.indb_flags & DBF_SPIFFY_AF_ANSI)) { + if (strchr(value, ESC_CHAR) || strchr(value, TAG_START)) { + char *vp = value; + as = parse_ansi_string(value); + safe_ansi_string(as, 0, as->len, value, &vp); + *vp = '\0'; + free_ansi_string(as); + } + } atr_new_add(i, name, value, owner, flags, derefs, w_lock, r_lock, modtime); } if (found != count) @@ -1605,18 +1676,16 @@ db_read_oldstyle(FILE * f) break; } - if (IsPlayer(i) && (strlen(o->name) > (Size_t) PLAYER_NAME_LIMIT)) { + if (IsPlayer(i) && (strlen(o->name) > (size_t) PLAYER_NAME_LIMIT)) { char buff[BUFFER_LEN + 1]; /* The name plus a NUL */ - strncpy(buff, o->name, PLAYER_NAME_LIMIT); - buff[PLAYER_NAME_LIMIT] = '\0'; + mush_strncpy(buff, o->name, PLAYER_NAME_LIMIT); set_name(i, buff); do_rawlog(LT_CHECK, T(" * Name of #%d is longer than the maximum, truncating.\n"), i); } else if (!IsPlayer(i) && (strlen(o->name) > OBJECT_NAME_LIMIT)) { char buff[OBJECT_NAME_LIMIT + 1]; /* The name plus a NUL */ - strncpy(buff, o->name, OBJECT_NAME_LIMIT); - buff[OBJECT_NAME_LIMIT] = '\0'; + mush_strncpy(buff, o->name, OBJECT_NAME_LIMIT); set_name(i, buff); do_rawlog(LT_CHECK, T(" * Name of #%d is longer than the maximum, truncating.\n"), @@ -2064,10 +2133,10 @@ db_read(FILE * f) 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); + if (size < 10) + size = 10; + hash_init(&htab_objdata, size, free_data); + hashinit(&htab_objdata_keys, 8); } void init_postconvert() { @@ -2129,7 +2198,9 @@ void init_postconvert() { * 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. @@ -2138,13 +2209,16 @@ void init_postconvert() { 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)) 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; @@ -2186,14 +2260,14 @@ create_minimal_db(void) dbref start_room, god, master_room, master_division; - int desc_flags = AF_VISUAL | AF_NOPROG | AF_PREFIXMATCH; + uint32_t desc_flags = AF_VISUAL | AF_NOPROG | AF_PREFIXMATCH; start_room = new_object(); /* #0 */ god = new_object(); /* #1 */ master_room = new_object(); /* #2 */ master_division = new_object(); /* #3 */ - init_objdata_htab(DB_INITIAL_SIZE, NULL); + init_objdata_htab(128, NULL); set_name(start_room, "Room Zero"); Type(start_room) = TYPE_ROOM; @@ -2211,9 +2285,9 @@ create_minimal_db(void) CreTime(god) = mudtime; ModTime(god) = (time_t) 0; SDIV(god).object = master_division; - add_lock(god, god, Basic_Lock, parse_boolexp(god, "=me", Basic_Lock), -1); - add_lock(god, god, Enter_Lock, parse_boolexp(god, "=me", Enter_Lock), -1); - add_lock(god, god, Use_Lock, parse_boolexp(god, "=me", Use_Lock), -1); + add_lock(god, god, Basic_Lock, parse_boolexp(god, "=me", Basic_Lock), LF_DEFAULT); + add_lock(god, god, Enter_Lock, parse_boolexp(god, "=me", Enter_Lock), LF_DEFAULT); + add_lock(god, god, Use_Lock, parse_boolexp(god, "=me", Use_Lock), LF_DEFAULT); atr_new_add(god, "DESCRIBE", "You see Number One.", god, desc_flags, 1, TRUE_BOOLEXP, TRUE_BOOLEXP, mudtime); #ifdef USE_MAILER atr_new_add(god, "MAILCURF", "0", god, AF_LOCKED | AF_NOPROG, 1, TRUE_BOOLEXP, TRUE_BOOLEXP, mudtime); @@ -2255,4 +2329,9 @@ create_minimal_db(void) SLEVEL(start_room) = LEVEL_SYSBUILDER; SLEVEL(master_room) = LEVEL_SYSCODER; SLEVEL(master_division) = LEVEL_DIRECTOR; + +#ifdef CHAT_SYSTEM + init_chatdb(); +#endif + mail_init(); } diff --git a/src/destroy.c b/src/destroy.c index 014a895..d3c5a08 100644 --- a/src/destroy.c +++ b/src/destroy.c @@ -54,7 +54,6 @@ #include "config.h" #include -#include #include #include #include @@ -781,9 +780,6 @@ free_object(dbref thing) current_state.garbage++; -#ifdef HAS_ASSERT - assert(IsGarbage(thing)); -#endif } static void @@ -951,12 +947,12 @@ free_get(void) if (nrecur++ == 20) { first_free = NOTHING; report(); - do_rawlog(LT_ERR, T("ERROR: Removed free list and continued\n")); + do_rawlog(LT_ERR, T("ERROR: Removed free list and continued")); return (NOTHING); } report(); - do_rawlog(LT_TRACE, T("ERROR: Object #%d should not be free\n"), newobj); - do_rawlog(LT_TRACE, T("ERROR: Corrupt free list, fixing\n")); + do_rawlog(LT_TRACE, T("ERROR: Object #%d should not be free"), newobj); + do_rawlog(LT_TRACE, T("ERROR: Corrupt free list, fixing")); fix_free_list(); temp = free_get(); nrecur--; @@ -1040,6 +1036,7 @@ dbck(void) check_connected_rooms(); check_zones(); check_divisions(); + validate_config(); /* Replacement for local_dbck */ MODULE_ITER(m) diff --git a/src/division.c b/src/division.c index 92dda68..86867ed 100644 --- a/src/division.c +++ b/src/division.c @@ -11,11 +11,7 @@ /* Required Includes {{{1 */ #include "copyrite.h" #include "config.h" -#ifdef I_STRING #include -#else -#include -#endif #include #include "conf.h" #include "externs.h" @@ -370,15 +366,15 @@ powers_read_all(FILE * in) ptab_init(ps_tab.powergroups); - db_read_this_labeled_number(in, "powercount", &count); + db_read_this_labeled_int(in, "powercount", &count); for (; count > 0; count--) power_read(in); - db_read_this_labeled_number(in, "aliascount", &count); + db_read_this_labeled_int(in, "aliascount", &count); for (; count > 0; count--) power_read_alias(in); - db_read_this_labeled_number(in, "powergroupcount", &count); + db_read_this_labeled_int(in, "powergroupcount", &count); for (; count > 0; count--) powergroup_read(in); @@ -494,7 +490,7 @@ power_write_all(FILE * file) if (!strcmp(pname, power->name)) num_powers++; - db_write_labeled_number(file, "powercount", num_powers); + db_write_labeled_int(file, "powercount", num_powers); for (power = ptab_firstentry_new(ps_tab.powers, pname); power; power = ptab_nextentry_new(ps_tab.powers, pname)) @@ -511,7 +507,7 @@ power_write_all(FILE * file) if (strcmp(pname, power->name)) i++; - db_write_labeled_number(file, "aliascount", i); + db_write_labeled_int(file, "aliascount", i); for (power = ptab_firstentry_new(ps_tab.powers, pname); power; power = ptab_nextentry_new(ps_tab.powers, pname)) if (strcmp(pname, power->name)) { @@ -522,7 +518,7 @@ power_write_all(FILE * file) ptab_firstentry_new(ps_tab.powergroups, pname); pgrp; pgrp = ptab_nextentry_new(ps_tab.powergroups, pname)) num_powers++; - db_write_labeled_number(file, "powergroupcount", num_powers); + db_write_labeled_int(file, "powergroupcount", num_powers); for (pgrp = ptab_firstentry_new(ps_tab.powergroups, pname); pgrp; pgrp = ptab_nextentry_new(ps_tab.powergroups, pname)) { db_write_labeled_string(file, " powergroupname", pgrp->name); diff --git a/src/extchat.c b/src/extchat.c index af55dd2..340b8e4 100644 --- a/src/extchat.c +++ b/src/extchat.c @@ -16,6 +16,8 @@ #endif #include #include "conf.h" + +#ifdef CHAT_SYSTEM #include "externs.h" #include "attrib.h" #include "mushdb.h" @@ -36,44 +38,18 @@ #include "dbio.h" #include "confmagic.h" -#ifdef CHAT_SYSTEM - -static struct { - unsigned oldchanflags, newchanflags; -} penn_conversion_table[] = -{ - {0x800, CHANNEL_INTERACT}, - {0, 0} -}; - -static struct { - int dbflags; - unsigned oldchanflags, newchanflags; -} dbflag_conversion_table[] = -{ - {0, 0, 0} -}; - -extern jmp_buf db_err; - -/** Evaluate a function and jump on error. */ -#define OUTPUT(fun) do { if ((fun) < 0) longjmp(db_err, 1); } while (0) -#define chan_cmd_match(x,y,z) (void)atr_comm_match(x, y, '$', ':', z, 0, NULL, NULL, NULL) static CHAN *new_channel(void); -static CHANLIST *new_chanlist(void); -static CHANUSER *new_user(dbref who); -static char *nv_eval(dbref thing, const char *code); -static void do_set_cobj _((dbref player, const char *name, const char *obj)); -static void do_reset_cobj _((dbref player, const char *name)); +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); -static int load_chatdb_oldstyle(FILE *fp); +static int load_chatdb_oldstyle(FILE * fp); static int load_channel(FILE * fp, CHAN *ch); static int load_chanusers(FILE * fp, CHAN *ch); -static int load_labeled_channel(FILE *fp, CHAN *ch, int iscobra, int dbflags); -static int load_labeled_chanusers(FILE *fp, CHAN *ch); +static int load_labeled_channel(FILE * fp, CHAN *ch); +static int load_labeled_chanusers(FILE * fp, CHAN *ch); static void insert_channel(CHAN **ch); static void remove_channel(CHAN *ch); static void insert_obj_chan(dbref who, CHAN **ch); @@ -98,9 +74,8 @@ static void channel_leave_self(dbref player, const char *name); 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); @@ -110,22 +85,27 @@ const char *chan_mod_lock = "ChanModLock"; /**< Name of modify lock */ const char *chan_see_lock = "ChanSeeLock"; /**< Name of see lock */ const char *chan_hide_lock = "ChanHideLock"; /**< Name of hide lock */ -#define CYES 1 /**< An affirmative. */ -#define CNO 0 /**< A negative. */ +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) -#define OnChannel(who,chan) ((ChanObj(chan) == who) || onchannel(who,chan)) int num_channels; /**< Number of channels defined */ CHAN *channels; /**< Pointer to channel list */ +extern int rhs_present; /* from command.c */ + static PRIV priv_table[] = { {"Disabled", 'D', CHANNEL_DISABLED, CHANNEL_DISABLED}, {"Admin", 'A', CHANNEL_ADMIN | CHANNEL_PLAYER, CHANNEL_ADMIN}, @@ -139,7 +119,6 @@ static PRIV priv_table[] = { {"NoNames", 'N', CHANNEL_NONAMES, CHANNEL_NONAMES}, {"NoCemit", 'C', CHANNEL_NOCEMIT, CHANNEL_NOCEMIT}, {"Interact", 'I', CHANNEL_INTERACT, CHANNEL_INTERACT}, - {"ChanObj", 'Z', CHANNEL_COBJ, CHANNEL_COBJ}, {NULL, '\0', 0, 0} }; @@ -190,6 +169,26 @@ onchannel(dbref who, CHAN *ch) } \ } while (0) +/** A macro to test if a channel exists and player's on it, and, + * if not, to notify. */ +#define test_channel_on(player,name,chan) \ + do { \ + chan = NULL; \ + switch (find_channel_partial_on(name,&chan,player)) { \ + case CMATCH_NONE: \ + notify(player, T ("CHAT: I don't recognize that channel.")); \ + return; \ + case CMATCH_AMBIG: \ + notify(player, T("CHAT: I don't know which channel you mean.")); \ + list_partial_matches(player, name, PMATCH_ALL); \ + return; \ + case CMATCH_EXACT: \ + case CMATCH_PARTIAL: \ + default: \ + break; \ + } \ + } while (0) + /*---------------------------------------------------------- * Loading and saving the chatdb * The chatdb's format is pretty straightforward @@ -200,8 +199,17 @@ onchannel(dbref who, CHAN *ch) void init_chatdb(void) { - num_channels = 0; - channels = NULL; + static bool init_called = 0; + if (!init_called) { + init_called = 1; + 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; + } } /** Load the chat database from a file. @@ -238,8 +246,7 @@ load_chatdb_oldstyle(FILE * fp) num_channels = i; /* Check for **END OF DUMP*** */ - fgets(buff, sizeof buff, fp); - if (!*buff) + if (!fgets(buff, sizeof buff, fp)) do_rawlog(LT_ERR, T("CHAT: No end-of-dump marker in the chat database.")); else if (strcmp(buff, EOD) != 0) do_rawlog(LT_ERR, T("CHAT: Trailing garbage in the chat database.")); @@ -257,7 +264,7 @@ extern char db_timestamp[]; int load_chatdb(FILE * fp) { - int i, flags, iscobra; + int i, flags; CHAN *ch; char buff[20]; char *chat_timestamp; @@ -273,11 +280,7 @@ load_chatdb(FILE * fp) i = fgetc(fp); - if (i == 'F') { - iscobra = 1; - } else if (i == 'V') { - iscobra = 0; - } else { + if (i != 'V') { do_rawlog(LT_ERR, T("CHAT: Invalid database format!")); longjmp(db_err, 1); } @@ -292,7 +295,7 @@ load_chatdb(FILE * fp) ("CHAT: warning: chatdb and game db were saved at different times!")); /* How many channels? */ - db_read_this_labeled_number(fp, "channels", &num_channels); + db_read_this_labeled_int(fp, "channels", &num_channels); if (num_channels > MAX_CHANNELS) return 0; @@ -301,7 +304,7 @@ load_chatdb(FILE * fp) ch = new_channel(); if (!ch) return 0; - if (!load_labeled_channel(fp, ch, iscobra, flags)) { + if (!load_labeled_channel(fp, ch)) { do_rawlog(LT_ERR, T("Unable to load channel %d."), i); free_channel(ch); return 0; @@ -311,8 +314,7 @@ load_chatdb(FILE * fp) num_channels = i; /* Check for **END OF DUMP*** */ - fgets(buff, sizeof buff, fp); - if (!*buff) + if (!fgets(buff, sizeof buff, fp)) do_rawlog(LT_ERR, T("CHAT: No end-of-dump marker in the chat database.")); else if (strcmp(buff, EOD) != 0) do_rawlog(LT_ERR, T("CHAT: Trailing garbage in the chat database.")); @@ -327,14 +329,13 @@ new_channel(void) { CHAN *ch; - ch = (CHAN *) mush_malloc(sizeof(CHAN), "CHAN"); + ch = slab_malloc(channel_slab, NULL); if (!ch) return NULL; ch->name[0] = '\0'; ch->title[0] = '\0'; ChanType(ch) = CHANNEL_DEFAULT_FLAGS; ChanCreator(ch) = NOTHING; - ChanObj(ch) = NOTHING; ChanCost(ch) = CHANNEL_COST; ChanNext(ch) = NULL; ChanNumMsgs(ch) = 0; @@ -355,10 +356,10 @@ new_channel(void) /* 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; @@ -394,7 +395,7 @@ static void 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 @@ -403,13 +404,12 @@ free_user(CHANUSER *u) 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)); - ChanType(ch) = getref(fp); + mush_strncpy(ChanTitle(ch), getstring_noalloc(fp), CHAN_TITLE_LEN); + ChanType(ch) = (privbits) getref(fp); ChanCreator(ch) = getref(fp); - ChanObj(ch) = NOTHING; ChanCost(ch) = getref(fp); ChanNumMsgs(ch) = 0; ChanJoinLock(ch) = getboolexp(fp, chan_join_lock); @@ -429,137 +429,44 @@ load_channel(FILE * fp, CHAN *ch) * successful, 0 otherwise. */ static int -load_labeled_channel(FILE * fp, CHAN *ch, int iscobra, int dbflags) +load_labeled_channel(FILE * fp, CHAN *ch) { - char *label, *value, c; + char *tmp; int i; - - enum known_labels { LBL_NAME, LBL_DESC, LBL_CFLAGS,LBL_CREATOR, LBL_COST, - LBL_LOCK, LBL_USERS, LBL_COBJ, LBL_JOIN, LBL_SPEAK, LBL_MODIFY, LBL_SEE, - LBL_HIDE, LBL_ERROR }; - struct label_table { - const char *label; - enum known_labels tag; - }; - struct subfield_t { - const char *subfield; - enum known_labels tag; - enum known_labels stag; - }; - struct label_table field[] = { - {"name", LBL_NAME}, - {"description", LBL_DESC}, - {"flags", LBL_CFLAGS}, - {"creator", LBL_CREATOR}, - {"cost", LBL_COST}, - {"lock", LBL_LOCK}, - {"users", LBL_USERS}, - {"cobj", LBL_COBJ}, - {NULL, LBL_ERROR} - }, *entry; - struct subfield_t subfield[] = { - {"join", LBL_LOCK, LBL_JOIN}, - {"speak", LBL_LOCK, LBL_SPEAK}, - {"modify", LBL_LOCK, LBL_MODIFY}, - {"see", LBL_LOCK, LBL_SEE}, - {"hide", LBL_LOCK, LBL_HIDE}, - {NULL, LBL_ERROR} - }, *sfptr; - enum known_labels the_label, the_subfield; - + dbref d; + char *label, *value; + + db_read_this_labeled_string(fp, "name", &tmp); + mush_strncpy(ChanName(ch), tmp, CHAN_NAME_LEN); + db_read_this_labeled_string(fp, "description", &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); + ChanCreator(ch) = d; + db_read_this_labeled_int(fp, "cost", &i); + ChanCost(ch) = i; ChanNumMsgs(ch) = 0; - while(1) { - c = fgetc(fp); - ungetc(c, fp); - if(c == '*') /* End of Dump Checking */ - break; + while (1) { db_read_labeled_string(fp, &label, &value); - the_label = LBL_ERROR; - for(entry = field; entry->label; entry++) - if(!strcasecmp(entry->label, label)) { - the_label = entry->tag; - break; - } - switch(the_label) { - case LBL_NAME: - strcpy(ChanName(ch), value); - break; - case LBL_DESC: - strcpy(ChanTitle(ch), value); - break; - case LBL_CFLAGS: - ChanType(ch) = parse_integer(value); - - if (!iscobra) - for (i = 0; penn_conversion_table[i].oldchanflags; i++) - if ((ChanType(ch) & penn_conversion_table[i].oldchanflags) - == penn_conversion_table[i].oldchanflags) - ChanType(ch) = (ChanType(ch) - & ~penn_conversion_table[i].oldchanflags) - | penn_conversion_table[i].newchanflags; - - for (i = 0; dbflag_conversion_table[i].dbflags; i++) - if (!(dbflags & dbflag_conversion_table[i].dbflags)) - if ((ChanType(ch) & dbflag_conversion_table[i].oldchanflags) - == dbflag_conversion_table[i].oldchanflags) - ChanType(ch) = (ChanType(ch) - & ~dbflag_conversion_table[i].oldchanflags) - | dbflag_conversion_table[i].newchanflags; - - break; - case LBL_CREATOR: - ChanCreator(ch) = qparse_dbref(value); - break; - case LBL_COBJ: - ChanObj(ch) = qparse_dbref(value); - break; - case LBL_COST: - ChanCost(ch) = parse_integer(value); - break; - case LBL_LOCK: - goto subfield_checks; - break; - case LBL_USERS: - ChanMaxUsers(ch) = ChanNumUsers(ch) = parse_integer(value); - ChanUsers(ch) = NULL; - if(ChanNumUsers(ch) > 0) - ChanNumUsers(ch) = load_labeled_chanusers(fp, ch); - return 1; - break; - case LBL_ERROR: - default: - do_rawlog(LT_ERR, T("Unrecgonized field '%s' in chatdatabase"), label); - return 0; - }; - continue; -subfield_checks: - for( sfptr = subfield; sfptr->subfield; sfptr++) - if((entry->tag == sfptr->tag) && !strcasecmp(sfptr->subfield, value) ) { - the_subfield = sfptr->stag; - break; - } - switch(the_subfield) { - case LBL_SPEAK: - ChanSpeakLock(ch) = getboolexp(fp, chan_speak_lock); - break; - case LBL_JOIN: - ChanJoinLock(ch) = getboolexp(fp, chan_join_lock); - break; - case LBL_MODIFY: - ChanModLock(ch) = getboolexp(fp, chan_mod_lock); - break; - case LBL_SEE: - ChanSeeLock(ch) = getboolexp(fp, chan_see_lock); - break; - case LBL_HIDE: - ChanHideLock(ch) = getboolexp(fp, chan_hide_lock); - break; - case LBL_ERROR: - default: - do_rawlog(LT_ERR, T("Unrecgonized lock subfield '%s' in chat database"), value); - break; - }; - } + if (strcmp(label, "lock")) + break; + else if (strcmp(value, "join") == 0) + ChanJoinLock(ch) = getboolexp(fp, chan_join_lock); + else if (strcmp(value, "speak") == 0) + ChanSpeakLock(ch) = getboolexp(fp, chan_speak_lock); + else if (strcmp(value, "modify") == 0) + ChanModLock(ch) = getboolexp(fp, chan_mod_lock); + else if (strcmp(value, "see") == 0) + ChanSeeLock(ch) = getboolexp(fp, chan_see_lock); + else if (strcmp(value, "hide") == 0) + ChanHideLock(ch) = getboolexp(fp, chan_hide_lock); + } + ChanNumUsers(ch) = parse_integer(value); + ChanMaxUsers(ch) = ChanNumUsers(ch); + ChanUsers(ch) = NULL; + if (ChanNumUsers(ch) > 0) + ChanNumUsers(ch) = load_labeled_chanusers(fp, ch); return 1; } @@ -575,7 +482,7 @@ load_chanusers(FILE * fp, CHAN *ch) 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; @@ -604,11 +511,11 @@ load_labeled_chanusers(FILE * fp, CHAN *ch) 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); - db_read_this_labeled_number(fp, "flags", &n); + 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++; @@ -616,8 +523,9 @@ load_labeled_chanusers(FILE * fp, CHAN *ch) /* But be sure to read (and discard) the player's info */ do_log(LT_ERR, 0, 0, T("Bad object #%d removed from channel %s"), player, ChanName(ch)); - db_read_this_labeled_number(fp, "flags", &n); + db_read_this_labeled_int(fp, "type", &n); db_read_this_labeled_string(fp, "title", &tmp); + ChanNumUsers(ch) -= 1; } } return num; @@ -700,7 +608,7 @@ insert_obj_chan(dbref who, CHAN **ch) if (!ch || !*ch) return; - tmp = new_chanlist(); + tmp = new_chanlist(Chanlist(who)); if (!tmp) return; tmp->chan = *ch; @@ -782,10 +690,10 @@ remove_all_obj_chan(dbref thing) 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; @@ -796,7 +704,7 @@ new_chanlist(void) static void free_chanlist(CHANLIST *cl) { - mush_free(cl, "CHANLIST"); + slab_free(chanlist_slab, cl); } @@ -823,7 +731,7 @@ insert_user(CHANUSER *user, CHAN *ch) 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; @@ -881,9 +789,9 @@ save_chatdb(FILE * fp) int default_flags = 0; /* How many channels? */ - OUTPUT(fprintf(fp, "+F%d\n", default_flags)); + OUTPUT(fprintf(fp, "+V%d\n", default_flags)); db_write_labeled_string(fp, "savedtime", show_time(mudtime, 1)); - db_write_labeled_number(fp, "channels", num_channels); + db_write_labeled_int(fp, "channels", num_channels); for (ch = channels; ch; ch = ch->next) { save_channel(fp, ch); } @@ -900,10 +808,9 @@ save_channel(FILE * fp, CHAN *ch) db_write_labeled_string(fp, " name", ChanName(ch)); db_write_labeled_string(fp, " description", ChanTitle(ch)); - db_write_labeled_number(fp, " flags", ChanType(ch)); + db_write_labeled_int(fp, " flags", ChanType(ch)); db_write_labeled_dbref(fp, " creator", ChanCreator(ch)); - db_write_labeled_dbref(fp, " cobj", ChanObj(ch)); - db_write_labeled_number(fp, " cost", ChanCost(ch)); + db_write_labeled_int(fp, " cost", ChanCost(ch)); db_write_labeled_string(fp, " lock", "join"); putboolexp(fp, ChanJoinLock(ch)); db_write_labeled_string(fp, " lock", "speak"); @@ -914,7 +821,7 @@ save_channel(FILE * fp, CHAN *ch) putboolexp(fp, ChanSeeLock(ch)); db_write_labeled_string(fp, " lock", "hide"); putboolexp(fp, ChanHideLock(ch)); - db_write_labeled_number(fp, " users", ChanNumUsers(ch)); + db_write_labeled_int(fp, " users", ChanNumUsers(ch)); for (cu = ChanUsers(ch); cu; cu = cu->next) save_chanuser(fp, cu); return 1; @@ -925,7 +832,7 @@ static int save_chanuser(FILE * fp, CHANUSER *user) { db_write_labeled_dbref(fp, " dbref", CUdbref(user)); - db_write_labeled_number(fp, " flags", CUtype(user)); + db_write_labeled_int(fp, " flags", CUtype(user)); db_write_labeled_string(fp, " title", CUtitle(user)); return 1; } @@ -998,14 +905,14 @@ find_channel(const char *name, CHAN **chan, dbref player) strcpy(cleanp, remove_markup(ChanName(p), NULL)); if (!strcasecmp(cleanname, cleanp)) { *chan = p; - if (Chan_Can_See(*chan, player) || OnChannel(player, *chan)) + if (Chan_Can_See(*chan, player) || onchannel(player, *chan)) return CMATCH_EXACT; else return CMATCH_NONE; } if (string_prefix(cleanp, name)) { /* Keep the alphabetically first channel if we've got one */ - if (Chan_Can_See(p, player) || OnChannel(player, p)) { + if (Chan_Can_See(p, player) || onchannel(player, p)) { if (!*chan) *chan = p; count++; @@ -1059,7 +966,7 @@ find_channel_partial(const char *name, CHAN **chan, dbref player) * player is on, keep using that one. Otherwise, this is * our best candidate so far. */ - if (!*chan || (!OnChannel(player, *chan) && OnChannel(player, p))) + if (!*chan || (!onchannel(player, *chan) && onchannel(player, p))) *chan = p; count++; } @@ -1136,13 +1043,13 @@ find_channel_partial_on(const char *name, CHAN **chan, dbref player) return CMATCH_NONE; cleanname = normalize_channel_name(name); for (p = channels; p; p = p->next) { - if (OnChannel(player, p)) { + if (onchannel(player, p)) { strcpy(cleanp, remove_markup(ChanName(p), NULL)); if (!strcasecmp(cleanname, cleanp)) { *chan = p; return CMATCH_EXACT; } - if (string_prefix(cleanp, cleanname) && OnChannel(player, p)) { + if (string_prefix(cleanp, cleanname) && onchannel(player, p)) { if (!*chan) *chan = p; count++; @@ -1185,7 +1092,7 @@ find_channel_partial_off(const char *name, CHAN **chan, dbref player) return CMATCH_NONE; cleanname = normalize_channel_name(name); for (p = channels; p; p = p->next) { - if (!OnChannel(player, p)) { + if (!onchannel(player, p)) { strcpy(cleanp, remove_markup(ChanName(p), NULL)); if (!strcasecmp(cleanname, cleanp)) { *chan = p; @@ -1259,7 +1166,7 @@ do_channel(dbref player, const char *name, const char *target, const char *com) test_channel(player, name, chan); if (!Chan_Can_See(chan, player)) { - if (OnChannel(player, chan)) + if (onchannel(player, chan)) notify_format(player, T("CHAT: You can't do that with channel <%s>."), ChanName(chan)); @@ -1282,11 +1189,12 @@ do_channel(dbref player, const char *name, const char *target, const char *com) if (!target || !*target) { notify(player, T("I don't understand what you want to do.")); return; - } else if ((victim = lookup_player(target)) != NOTHING) ; - else if (Channel_Object(chan)) + } + + victim = lookup_player(target); + if (victim == NOTHING && Channel_Object(chan)) victim = match_result(player, target, TYPE_THING, MAT_OBJECTS); - else - victim = NOTHING; + if (!GoodObject(victim)) { notify(player, T("Invalid target.")); return; @@ -1307,7 +1215,7 @@ do_channel(dbref player, const char *name, const char *target, const char *com) return; } /* Is victim already on the channel? */ - if (OnChannel(victim, chan)) { + if (onchannel(victim, chan)) { notify_format(player, T("%s is already on channel <%s>."), Name(victim), ChanName(chan)); @@ -1334,8 +1242,8 @@ do_channel(dbref player, const char *name, const char *target, const char *com) 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 { @@ -1356,12 +1264,12 @@ do_channel(dbref player, const char *name, const char *target, const char *com) return; } u = onchannel(victim, chan); - strcpy(title, (u &&CUtitle(u)) ? CUtitle(u) : ""); + 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>."), @@ -1429,11 +1337,11 @@ channel_join_self(dbref player, const char *name) } } if (insert_user_by_dbref(player, chan)) { - notify_format(player, T("CHAT: You join channel %s."), ChanObjName(chan)); + 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 */ @@ -1471,11 +1379,11 @@ channel_leave_self(dbref player, const char *name) break; } u = onchannel(player, chan); - strcpy(title, (u &&CUtitle(u)) ? CUtitle(u) : ""); + 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 */ @@ -1564,6 +1472,9 @@ do_chat_by_name(dbref player, const char *name, const char *msg, int source) if (!ChanUseFirstMatch(player)) { notify(player, T("CHAT: I don't know which channel you mean.")); list_partial_matches(player, name, PMATCH_ON); + notify(player, + T + ("CHAT: You may wish to set the CHAN_USEFIRSTMATCH flag on yourself.")); return 1; } case CMATCH_EXACT: @@ -1592,10 +1503,11 @@ do_chat(dbref player, CHAN *chan, const char *arg1) { CHANUSER *u; const char *gap; + char type; const char *someone = "Someone"; char *title; const char *name; - int canhear; + bool canhear; if (!Chan_Ok_Type(chan, player)) { notify_format(player, @@ -1604,7 +1516,7 @@ do_chat(dbref player, CHAN *chan, const char *arg1) ChanName(chan)); return; } - if (!Chan_Can_Speak(chan, player)) { + if (!Loud(player) && !Chan_Can_Speak(chan, player)) { if (Chan_Can_See(chan, player)) notify_format(player, T("Sorry, you're not allowed to speak on channel <%s>."), @@ -1616,18 +1528,13 @@ do_chat(dbref player, CHAN *chan, const char *arg1) u = onchannel(player, chan); canhear = u ? !Chanuser_Gag(u) : 0; /* If the channel isn't open, you must hear it in order to speak */ - if (!Channel_Open(chan) && ChanObj(chan) != player) { + if (!Channel_Open(chan)) { if (!u) { notify(player, T("You must be on that channel to speak on it.")); return; } else if (!canhear) { notify(player, T("You must stop gagging that channel to speak on it.")); return; -#ifdef RPMODE_SYS - } else if(RPMODE(player) && !Can_RPCHAT(player)) { - notify(player, T("You can't do that in RPMODE.")); - return; -#endif /* RPMODE_SYS */ } } @@ -1636,8 +1543,8 @@ do_chat(dbref player, CHAN *chan, const char *arg1) return; } - if (!Channel_NoTitles(chan) && u &&CUtitle(u) && *CUtitle(u)) - title = CUtitle(u); + if (!Channel_NoTitles(chan) && u && CUtitle(u) && *CUtitle(u)) + title = CUtitle(u); else title = NULL; if (Channel_NoNames(chan)) @@ -1649,39 +1556,38 @@ do_chat(dbref player, CHAN *chan, const char *arg1) /* 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", ChanObjName(chan), - title ? title : "", title ? ANSI_NORMAL : "", - (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_NORMAL : "", + title ? title : "", title ? ANSI_ENDALL : "", (title && name) ? " " : "", name ? name : "", gap, arg1); break; default: if (CHAT_STRIP_QUOTE && (*arg1 == SAY_TOKEN)) arg1 = arg1 + 1; - channel_broadcast(chan, player, 0, T("%s %s%s%s%s says, \"%s\""), - ChanObjName(chan), title ? title : "", - title ? ANSI_NORMAL : "", (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\""), ChanName(chan), title ? title : "", - title ? ANSI_NORMAL : "", (title && name) ? " " : "", + title ? ANSI_ENDALL : "", (title && name) ? " " : "", name ? name : "", arg1); break; } - if(ChanObjCheck(chan) == 1 && player != ChanObj(chan)) - chan_cmd_match(ChanObj(chan), player, arg1); - ChanNumMsgs(chan)++; } @@ -1700,6 +1606,7 @@ do_cemit(dbref player, const char *name, const char *msg, int flags) CHAN *chan = NULL; CHANUSER *u; int canhear; + int override_checks = 0; if (!name || !*name) { notify(player, T("That is not a valid channel.")); @@ -1713,19 +1620,25 @@ do_cemit(dbref player, const char *name, const char *msg, int flags) notify(player, T("I don't know which channel you mean.")); list_partial_matches(player, name, PMATCH_ALL); return; + default: + break; } if (!Chan_Can_See(chan, player)) { notify(player, T("CHAT: I don't recognize that channel.")); return; } - if (!Chan_Ok_Type(chan, player)) { + /* If the cemitter is both See_All and Pemit_All, always allow them + * to @cemit, as they could iterate over connected players, examine + * their channels, and pemit to them anyway. + */ + if (!override_checks && !Chan_Ok_Type(chan, player)) { notify_format(player, T ("Sorry, you're not the right type to be on channel <%s>."), ChanName(chan)); return; } - if (!Chan_Can_Cemit(chan, player)) { + if (!override_checks && !Chan_Can_Cemit(chan, player)) { notify_format(player, T("Sorry, you're not allowed to @cemit on channel <%s>."), ChanName(chan)); @@ -1734,18 +1647,13 @@ do_cemit(dbref player, const char *name, const char *msg, int flags) u = onchannel(player, chan); canhear = u ? !Chanuser_Gag(u) : 0; /* If the channel isn't open, you must hear it in order to speak */ - if (!Channel_Open(chan)) { + if (!override_checks && !Channel_Open(chan)) { if (!u) { notify(player, T("You must be on that channel to speak on it.")); return; } else if (!canhear) { notify(player, T("You must stop gagging that channel to speak on it.")); return; -#ifdef RPMODE_SYS - } else if(RPMODE(player) && !Can_RPCHAT(player)) { - notify(player, T("You can't do that in RPMODE.")); - return; -#endif /* RPMODE_SYS */ } } @@ -1754,11 +1662,11 @@ do_cemit(dbref player, const char *name, const char *msg, int flags) return; } if (!(flags & PEMIT_SILENT)) - channel_broadcast(chan, player, (flags & PEMIT_SPOOF) ? 0 : CB_NOSPOOF, - "%s %s", ChanObjName(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)++; @@ -1779,10 +1687,11 @@ void do_chan_admin(dbref player, char *name, const char *perms, int flag) { CHAN *chan = NULL, *temp = NULL; - long int type; + privbits type; int res; boolexp key; char old[CHAN_NAME_LEN]; + char announcebuff[BUFFER_LEN]; if (!name || !*name) { notify(player, T("You must specify a channel.")); @@ -1835,13 +1744,6 @@ do_chan_admin(dbref player, char *name, const char *perms, int flag) } if (type & CHANNEL_DISABLED) notify(player, T("Warning: channel will be created disabled.")); - - /* Check if they're trying to create it as a chanobj channel, if so reject them */ - if(type & CHANNEL_COBJ) { - notify(player,"CHAT: Channels can not be created with chanobj type."); - return; - } - /* Can the player afford it? There's a cost */ if (!payfor(Owner(player), CHANNEL_COST)) { notify_format(player, T("You can't afford the %d %s."), CHANNEL_COST, @@ -1857,7 +1759,7 @@ do_chan_admin(dbref player, char *name, const char *perms, int flag) } 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; @@ -1867,7 +1769,7 @@ do_chan_admin(dbref player, char *name, const char *perms, int flag) if (type) ChanType(chan) = type; ChanCreator(chan) = Owner(player); - strcpy(ChanName(chan), name); + mush_strncpy(ChanName(chan), name, CHAN_NAME_LEN); insert_channel(&chan); notify_format(player, T("CHAT: Channel <%s> created."), ChanName(chan)); break; @@ -1914,9 +1816,11 @@ do_chan_admin(dbref player, char *name, const char *perms, int flag) 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: @@ -1927,11 +1831,10 @@ do_chan_admin(dbref player, char *name, const char *perms, int flag) } /* get the permissions. Invalid specs default to no change */ type = string_to_privs(priv_table, perms, ChanType(chan)); - if (!Chan_Can_Priv(player, type, ChanType(chan))) { + if (!Chan_Can_Priv(player, type)) { notify(player, T("You can't make channels that type.")); return; - } - + } if (type & CHANNEL_DISABLED) notify(player, T("Warning: channel will be disabled.")); if (type == ChanType(chan)) { @@ -1955,11 +1858,11 @@ ok_channel_name(const char *n) const char *p; char name[BUFFER_LEN]; - strcpy(name, remove_markup(n, NULL)); - - if (!*name) + if (!n || !*n) return 0; + mush_strncpy(name, remove_markup(n, NULL), BUFFER_LEN); + /* No leading spaces */ if (isspace((unsigned char) *name)) return 0; @@ -2023,7 +1926,7 @@ do_chan_user_flags(dbref player, char *name, const char *isyn, int flag, break; } } else { - test_channel(player, name, c); + test_channel_on(player, name, c); } /* channel loop */ @@ -2130,8 +2033,25 @@ do_chan_title(dbref player, const char *name, const char *title) notify(player, T("You must specify a channel.")); return; } + + test_channel(player, name, c); + u = onchannel(player, c); + if (!u) { + notify_format(player, T("You are not on channel <%s>."), ChanName(c)); + return; + } + + if (!rhs_present) { + if (strlen(CUtitle(u)) == 0) + notify_format(player, T("You have no title set on <%s>."), ChanName(c)); + else + notify_format(player, T("Your title on <%s> is '%s'."), ChanName(c), + CUtitle(u)); + return; + } + if (!title) - title = ""; + title = (const char *) ""; if (strlen(title) >= CU_TITLE_LEN) { notify(player, T("Title too long.")); @@ -2145,17 +2065,12 @@ do_chan_title(dbref player, const char *name, const char *title) return; } } - test_channel(player, name, c); - u = onchannel(player, c); - if (!u) { - notify_format(player, T("You are not on channel <%s>."), ChanName(c)); - return; - } + strcpy(CUtitle(u), title); if (!Quiet(player)) - notify_format(player, T("Title %s for %schannel %s."), + notify_format(player, T("Title %s for %schannel <%s>."), *title ? T("set") : T("cleared"), - Channel_NoTitles(c) ? "(NoTitles) " : "", ChanObjName(c)); + Channel_NoTitles(c) ? "(NoTitles) " : "", ChanName(c)); return; } @@ -2174,25 +2089,26 @@ do_channel_list(dbref player, const char *partname) CHANUSER *u; char numusers[BUFFER_LEN]; char cleanname[CHAN_NAME_LEN]; - char blanks[31]; - int len; + char blanks[CHAN_NAME_LEN]; + size_t len; int numblanks; if (SUPPORT_PUEBLO) - notify_noenter(player, tprintf("%cSAMP%c", TAG_START, TAG_END)); + notify_noenter(player, open_tag("SAMP")); notify_format(player, "%-30s %-5s %8s %-16s %-8s %-3s", - "Name", "Users", "Msgs", T("Chan Type"), "Status", "Buf"); + T("Name"), T("Users"), T("Msgs"), T("Chan Type"), T("Status"), + T("Buf")); for (c = channels; c; c = c->next) { strcpy(cleanname, remove_markup(ChanName(c), NULL)); if (Chan_Can_See(c, player) && string_prefix(cleanname, partname)) { u = onchannel(player, c); if (SUPPORT_PUEBLO) - sprintf(numusers, - "%cA XCH_CMD=\"@channel/who %s\" XCH_HINT=\"See who's on this channel now\"%c%5ld%c/A%c", - TAG_START, cleanname, TAG_END, ChanNumUsers(c), - TAG_START, TAG_END); + snprintf(numusers, BUFFER_LEN, + "%c%cA XCH_CMD=\"@channel/who %s\" XCH_HINT=\"See who's on this channel now\"%c%5d%c%c/A%c", + TAG_START, MARKUP_HTML, cleanname, TAG_END, ChanNumUsers(c), + TAG_START, MARKUP_HTML, TAG_END); else - sprintf(numusers, "%5ld", ChanNumUsers(c)); + sprintf(numusers, "%5d", ChanNumUsers(c)); /* Display length is strlen(cleanname), but actual length is * strlen(ChanName(c)). There are two different cases: * 1. actual length <= 30. No problems. @@ -2213,15 +2129,14 @@ do_channel_list(dbref player, const char *partname) blanks[0] = '\0'; } notify_format(player, - "%-30s%s %s %8ld [%c%c%c%c%c%c%c%c %c%c%c%c%c%c] [%-3s %c%c] %3d", + "%-30s%s %s %8ld [%c%c%c%c%c%c%c %c%c%c%c%c%c] [%-3s %c%c] %3d", ChanName(c), blanks, numusers, ChanNumMsgs(c), Channel_Disabled(c) ? 'D' : '-', Channel_Player(c) ? 'P' : '-', Channel_Object(c) ? 'O' : '-', - Channel_Admin(c) ? 'A' : (Channel_Director(c) ? 'W' : '-'), + Channel_Admin(c) ? 'A' : (Channel_Wizard(c) ? 'W' : '-'), Channel_Quiet(c) ? 'Q' : '-', Channel_CanHide(c) ? 'H' : '-', Channel_Open(c) ? 'o' : '-', - (ChanType(c) & CHANNEL_COBJ) ? 'Z' : '-', /* Locks */ ChanJoinLock(c) != TRUE_BOOLEXP ? 'j' : '-', ChanSpeakLock(c) != TRUE_BOOLEXP ? 's' : '-', @@ -2231,14 +2146,14 @@ do_channel_list(dbref player, const char *partname) /* Does the player own it? */ ChanCreator(c) == player ? '*' : '-', /* User status */ - u ? (Chanuser_Gag(u) ? "Gag" : "On") : "Off", - (u &&Chanuser_Quiet(u)) ? 'Q' : ' ', - (u &&Chanuser_Hide(u)) ? 'H' : ' ', - bufferq_lines(ChanBufferQ(c))); + u ? (Chanuser_Gag(u) ? T("Gag") : T("On")) : T("Off"), + (u && Chanuser_Quiet(u)) ? 'Q' : ' ', + (u && Chanuser_Hide(u)) ? 'H' : ' ', + bufferq_blocks(ChanBufferQ(c))); } } if (SUPPORT_PUEBLO) - notify_noenter(player, tprintf("%c/SAMP%c", TAG_START, TAG_END)); + notify_noenter(player, close_tag("SAMP")); } static char * @@ -2264,35 +2179,6 @@ list_cuflags(CHANUSER *u, int verbose) return tbuf1; } -FUNCTION(fun_cobj) { -CHAN *c; - - switch(find_channel(args[0], &c, executor)) { - case CMATCH_NONE: - safe_str("#-1 NO SUCH CHANNEL", buff, bp); - return; - case CMATCH_AMBIG: - safe_str("#-2 AMBIGUOUS CHANNEL MATCH", buff, bp); - return; - } - - if(!ChanObjCheck(c)) { - safe_str("#-1 NO CHANOBJ SET", buff, bp); - return; - } - if((executor == ChanCreator(c)) || Director(executor) || - Visual(ChanObj(c)) || controls(executor, Owner(ChanCreator(c)))) { - - safe_str(tprintf("#%ld", ChanObj(c)), buff, bp); - return; - } - else - { - safe_str("#-1 PERMISSION DENIED", buff, bp); - return; - } -} - /* ARGSUSED */ FUNCTION(fun_cflags) { @@ -2370,17 +2256,70 @@ FUNCTION(fun_cinfo) safe_str(T("#-1 NO SUCH CHANNEL"), buff, bp); return; } - if (string_prefix(called_as, "CD")) + if (string_prefix(called_as, "CD")) { safe_str(ChanTitle(c), buff, bp); - else if (string_prefix(called_as, "CB")) { - if(ChanBufferQ(c) != NULL) + } else if (string_prefix(called_as, "CB")) { + if (ChanBufferQ(c) != NULL) { safe_integer(BufferQSize(ChanBufferQ(c)), buff, bp); - else - safe_chr('0', buff, bp); - } else if (string_prefix(called_as, "CU")) + } else { + safe_integer(0, buff, bp); + } + } else if (string_prefix(called_as, "CU")) { safe_integer(ChanNumUsers(c), buff, bp); - else if (string_prefix(called_as, "CM")) - safe_integer(ChanNumMsgs(c), buff, bp); + } else if (string_prefix(called_as, "CM")) { + safe_format(buff, bp, "%lu", ChanNumMsgs(c)); + } + } +} + +/* ARGSUSED */ +FUNCTION(fun_cbufferadd) +{ + CHAN *c; + dbref victim; + + // Person must be able to do nospoof cemits. + if (!command_check_byname(executor, "@cemit") || fun->flags & FN_NOSIDEFX) { + safe_str(T(e_perm), buff, bp); + return; + } + // Find the channel. + if (!args[0] || !*args[0]) { + safe_str(T("#-1 NO CHANNEL GIVEN"), buff, bp); + return; + } + // Make sure we have text. + if (!args[1] || !*args[1]) { + safe_str(T("#-1 NO TEXT GIVEN"), buff, bp); + return; + } + + victim = executor; + // Do we spoof somebody else? + if (nargs == 3 && parse_boolean(args[2])) { + // Person must be able to do nospoof cemits. + if (!command_check_byname(executor, "@nscemit") || fun->flags & FN_NOSIDEFX) { + safe_str(T(e_perm), buff, bp); + return; + } + victim = enactor; + } + // Get the message. + switch (find_channel(args[0], &c, executor)) { + case CMATCH_NONE: + safe_str(T("#-1 NO SUCH CHANNEL"), buff, bp); + return; + case CMATCH_AMBIG: + safe_str(T("#-1 AMBIGUOUS CHANNEL NAME"), buff, bp); + return; + default: + if (!Chan_Can_Modify(c, executor)) { + safe_str(T(e_perm), buff, bp); + } else if (ChanBufferQ(c) != NULL) { + add_to_bufferq(ChanBufferQ(c), 0, victim, args[1]); + } else { + safe_str(T("#-1 CHANNEL DOES NOT HAVE A BUFFER"), buff, bp); + } } } @@ -2438,14 +2377,14 @@ FUNCTION(fun_ctitle) return; } if (CUtitle(u)) - safe_str(CUtitle(u), buff, bp); + safe_str(CUtitle(u), buff, bp); break; } } /* ARGSUSED */ FUNCTION(fun_cstatus) -{ +{ /* cstatus(,) returns the object's status on that chan. * You must pass the channel's see-lock, and * either you must either be able to examine , or @@ -2454,11 +2393,11 @@ FUNCTION(fun_cstatus) CHAN *c; CHANUSER *u; dbref thing; - + if (!args[0] || !*args[0]) { safe_str(T("#-1 NO CHANNEL GIVEN"), buff, bp); return; - } + } switch (find_channel(args[0], &c, executor)) { case CMATCH_NONE: safe_str(T("#-1 NO SUCH CHANNEL"), buff, bp); @@ -2477,7 +2416,7 @@ FUNCTION(fun_cstatus) return; } u = onchannel(thing, c); - if (!u ||(!IsThing(thing) && !Connected(thing))) { + if (!u || (!IsThing(thing) && !Connected(thing))) { /* Easy, they're not on it or a disconnected player */ safe_str("Off", buff, bp); return; @@ -2532,8 +2471,8 @@ channel_wipe(dbref player, CHAN *chan) nextu = u->next; victim = CUdbref(u); if (remove_user(u, chan)) - notify_format(victim, T("CHAT: %s has removed all users from <%s>."), - Name(player), ChanName(chan)); + notify_format(victim, T("CHAT: %s has removed all users from <%s>."), + Name(player), ChanName(chan)); } ChanNumUsers(chan) = 0; return; @@ -2586,7 +2525,7 @@ do_chan_chown(dbref player, const char *name, const char *newowner) /* Find the channel */ test_channel(player, name, c); /* Find the victim */ - if (!newowner || (victim = lookup_player(newowner)) == NOTHING) { + if (!newowner || ((victim = lookup_player(newowner)) == NOTHING)) { notify(player, T("CHAT: Invalid owner.")); return; } @@ -2649,7 +2588,7 @@ do_chan_lock(dbref player, const char *name, const char *lockstr, int whichlock) test_channel(player, name, c); /* Make sure the player has permission */ if (!Chan_Can_Modify(c, player)) { - notify_format(player, T("CHAT: Channel %s resists."), ChanObjName(c)); + notify_format(player, T("CHAT: Channel <%s> resists."), ChanName(c)); return; } /* Ok, let's do it */ @@ -2747,19 +2686,12 @@ do_chan_what(dbref player, const char *partname) notify_format(player, T("Description: %s"), ChanTitle(c)); notify_format(player, T("Owner: %s"), Name(ChanCreator(c))); notify_format(player, T("Flags: %s"), - privs_to_string(priv_table, ChanType(c))); - if(ChanType(c) & CHANNEL_COBJ) { - if(player == ChanCreator(c) || Director(player) - || Visual(ChanObj(c)) - || controls(player, Owner(ChanCreator(c)))) - notify_format(player, "Channel object: %s", - object_header(player, ChanObj(c))); - } - + privs_to_string(priv_table, ChanType(c))); if (ChanBufferQ(c)) notify_format(player, - T("Recall buffer: %dk, can hold %d."), - BufferQSize(ChanBufferQ(c)), bufferq_lines(ChanBufferQ(c))); + T("Recall buffer: %dk, with %d lines stored."), + BufferQSize(ChanBufferQ(c)), + bufferq_lines(ChanBufferQ(c))); found++; } } @@ -2803,8 +2735,6 @@ do_chan_decompile(dbref player, const char *name, int brief) privs_to_string(priv_table, ChanType(c))); notify_format(player, "@channel/chown %s = %s", ChanName(c), Name(ChanCreator(c))); - if(ChanObj(c) != NOTHING) - notify_format(player, "@cobj %s=%s", ChanName(c), unparse_dbref(ChanObj(c))); if (ChanModLock(c) != TRUE_BOOLEXP) notify_format(player, "@clock/mod %s = %s", ChanName(c), unparse_boolexp(player, ChanModLock(c), UB_MEREF)); @@ -2825,13 +2755,13 @@ do_chan_decompile(dbref player, const char *name, int brief) ChanTitle(c)); if (ChanBufferQ(c)) notify_format(player, "@channel/buffer %s = %d", ChanName(c), - bufferq_lines(ChanBufferQ(c))); + bufferq_blocks(ChanBufferQ(c))); if (!brief) { for (u = ChanUsers(c); u; u = u->next) { if (!Chanuser_Hide(u) || Priv_Who(player)) - notify_format(player, "@channel/on %s = %s", ChanName(c), - Name(CUdbref(u))); + notify_format(player, "@channel/on %s = %s", ChanName(c), + Name(CUdbref(u))); } } } @@ -2847,7 +2777,7 @@ do_channel_who(dbref player, CHAN *chan) char *bp; CHANUSER *u; dbref who; - int sf, i = 0; + int i = 0; bp = tbuf1; for (u = ChanUsers(chan); u; u = u->next) { who = CUdbref(u); @@ -2858,33 +2788,12 @@ do_channel_who(dbref player, CHAN *chan) safe_str(Name(who), tbuf1, &bp); if (IsThing(who)) safe_format(tbuf1, &bp, "(#%d)", who); - sf = 0; - if (Chanuser_Hide(u) || Chanuser_Gag(u) -#ifdef RPMODE_SYS - || (RPMODE(u->who) && !Can_RPCHAT(u->who)) -#endif /* RPMODE_SYS */ - ) { - safe_str(" (", tbuf1, &bp); - sf++; - } - if (Chanuser_Hide(u)) { - safe_str("hidden", tbuf1, &bp); - sf++; - } - if(Chanuser_Gag(u)) { - if(sf > 1) safe_chr(',', tbuf1, &bp); - safe_str("gagging", tbuf1, &bp); - sf++; - } -#ifdef RPMODE_SYS - if(RPMODE(u->who) && !Can_RPCHAT(u->who)) { - if(sf > 1) safe_chr(',', tbuf1, &bp); - safe_str("rpgag", tbuf1, &bp); - sf++; - } -#endif /* RPMODE_SYS */ - if(sf > 0) - safe_chr(')', tbuf1, &bp); + if (Chanuser_Hide(u) && Chanuser_Gag(u)) + safe_str(" (hidden,gagging)", tbuf1, &bp); + else if (Chanuser_Hide(u)) + safe_str(" (hidden)", tbuf1, &bp); + else if (Chanuser_Gag(u)) + safe_str(" (gagging)", tbuf1, &bp); } } *bp = '\0'; @@ -2993,19 +2902,19 @@ yesno(const char *str) switch (str[0]) { case 'y': case 'Y': - return CYES; + return YES; case 'n': case 'N': - return CNO; + return NO; case 'o': case 'O': switch (str[1]) { case 'n': case 'N': - return CYES; + return YES; case 'f': case 'F': - return CNO; + return NO; default: return ERR; } @@ -3041,19 +2950,14 @@ chat_player_announce(dbref player, char *msg, int ungag) { 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_Director(c) + 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; @@ -3069,16 +2973,21 @@ const char * channel_description(dbref player) { static char buf[BUFFER_LEN]; + char *bp; CHANLIST *c; - *buf = '\0'; + bp = buf; if (Chanlist(player)) { - strcpy(buf, T("Channels:")); - for (c = Chanlist(player); c; c = c->next) - sprintf(buf, "%s %s", buf, ChanName(c->chan)); + safe_str(T("Channels:"), buf, &bp); + for (c = Chanlist(player); c; c = c->next) { + safe_chr(' ', buf, &bp); + safe_str(ChanName(c->chan), buf, &bp); + } } else if (IsPlayer(player)) - strcpy(buf, T("Channels: *NONE*")); + safe_str(T("Channels: *NONE*"), buf, &bp); + + *bp = '\0'; return buf; } @@ -3110,7 +3019,7 @@ FUNCTION(fun_channels) return; can_ex = Can_Examine(executor, it); for (cl = Chanlist(it); cl; cl = cl->next) { - if (can_ex || ((u = onchannel(it, cl->chan)) &&!Chanuser_Hide(u) + if (can_ex || ((u = onchannel(it, cl->chan)) && !Chanuser_Hide(u) && onchannel(executor, cl->chan))) { if (!first) safe_chr(sep, buff, bp); @@ -3162,6 +3071,8 @@ FUNCTION(fun_clock) case CMATCH_AMBIG: safe_str("#-2 AMBIGUOUS CHANNEL MATCH", buff, bp); return; + default: + break; } if (!strcasecmp(p, "JOIN")) { @@ -3198,7 +3109,7 @@ FUNCTION(fun_clock) } if (Chan_Can_Decomp(c, executor)) { - safe_str(unparse_boolexp(executor, lock_ptr, 1), buff, bp); + safe_str(unparse_boolexp(executor, lock_ptr, UB_MEREF), buff, bp); return; } else { safe_str(T(e_perm), buff, bp); @@ -3228,7 +3139,9 @@ FUNCTION(fun_crecall) { 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; @@ -3245,11 +3158,14 @@ FUNCTION(fun_crecall) } 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; @@ -3284,7 +3200,7 @@ FUNCTION(fun_crecall) } u = onchannel(executor, chan); - if (!u &&!Chan_Can_Access(chan, executor)) { + if (!u && !Chan_Can_Access(chan, executor)) { safe_str(T(e_perm), buff, bp); return; } @@ -3294,6 +3210,15 @@ FUNCTION(fun_crecall) 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)) @@ -3332,17 +3257,23 @@ FUNCTION(fun_crecall) } num_lines--; } + + } -COMMAND (cmd_cemit) { +COMMAND(cmd_cemit) +{ int spflags = !strcmp(cmd->name, "@NSCEMIT") ? PEMIT_SPOOF : 0; SPOOF(player, cause, sw); - if (!SW_ISSET(sw, SWITCH_NOISY)) + if (SW_ISSET(sw, SWITCH_SILENT)) + spflags |= PEMIT_SILENT; + else if (!SW_ISSET(sw, SWITCH_NOISY) && options.noisy_cemit == 0) spflags |= PEMIT_SILENT; do_cemit(player, arg_left, arg_right, spflags); } -COMMAND (cmd_channel) { +COMMAND(cmd_channel) +{ if (switches) do_channel(player, arg_left, args_right[1], switches); else if (SW_ISSET(sw, SWITCH_LIST)) @@ -3389,20 +3320,13 @@ COMMAND (cmd_channel) { do_channel(player, arg_left, NULL, args_right[1]); } -COMMAND (cmd_chat) { +COMMAND(cmd_chat) +{ do_chat_by_name(player, arg_left, arg_right, 1); } -COMMAND(cmd_cobj) { - if(SW_ISSET(sw, SWITCH_RESET)) { - do_reset_cobj(player,arg_left); - return; - } - do_set_cobj(player, arg_left, arg_right); -} - - -COMMAND (cmd_clock) { +COMMAND(cmd_clock) +{ if (SW_ISSET(sw, SWITCH_JOIN)) do_chan_lock(player, arg_left, arg_right, CL_JOIN); else if (SW_ISSET(sw, SWITCH_SPEAK)) @@ -3440,24 +3364,22 @@ na_channel(dbref current, void *data) nu = u->next; cont = (!GoodObject(current) || (nac->checkquiet && Chanuser_Quiet(u)) || - Chanuser_Gag(u) -#ifdef RPMODE_SYS - || (RPMODE(current) && !Can_RPCHAT(current)) -#endif - || (IsPlayer(current) && !Connected(current))); + Chanuser_Gag(u) || (IsPlayer(current) && !Connected(current))); } while (cont); nac->u = nu; 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; @@ -3466,8 +3388,17 @@ channel_broadcast(CHAN *channel, dbref player, int flags, const char *fmt, ...) #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)) @@ -3483,12 +3414,39 @@ channel_broadcast(CHAN *channel, dbref player, int flags, const char *fmt, ...) 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 (!vmessageformat(current, "CHATFORMAT", player, + na_flags | ((flags & CB_NOSPOOF) ? 0 : NA_SPOOF), + 6, 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); @@ -3503,7 +3461,7 @@ channel_broadcast(CHAN *channel, dbref player, int flags, const char *fmt, ...) * \endverbatim * \param player the enactor. * \param name the name of the channel. - * \param lineinfo pointer to array containing lines, optional start + * \param lineinfo point to array containing lines, optoinal start * \param quiet if true, don't show timestamps. */ void @@ -3511,17 +3469,18 @@ do_chan_recall(dbref player, const char *name, char *lineinfo[], int quiet) { 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; char *stamp; dbref speaker; int type; - if (!name || !*name) { notify(player, T("You need to specify a channel.")); return; @@ -3540,11 +3499,17 @@ do_chan_recall(dbref player, const char *name, char *lineinfo[], int quiet) 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; @@ -3552,7 +3517,7 @@ do_chan_recall(dbref player, const char *name, char *lineinfo[], int quiet) test_channel(player, name, chan); if (!Chan_Can_See(chan, player)) { - if (OnChannel(player, chan)) + if (onchannel(player, chan)) notify_format(player, T("CHAT: You can't do that with channel <%s>."), ChanName(chan)); @@ -3561,14 +3526,24 @@ do_chan_recall(dbref player, const char *name, char *lineinfo[], int quiet) return; } u = onchannel(player, chan); - if (!u &&!Chan_Can_Access(chan, player)) { - notify(player, T("CHAT: You must join a channel to recall from it.")); + if (!u && !Chan_Can_Join(chan, player)) { + notify(player, + T("CHAT: You must be able to join a channel to recall from it.")); return; } if (!ChanBufferQ(chan)) { 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)) @@ -3576,7 +3551,6 @@ do_chan_recall(dbref player, const char *name, char *lineinfo[], int quiet) 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) { @@ -3626,7 +3600,6 @@ do_chan_buffer(dbref player, const char *name, const char *lines) { CHAN *chan; int size; - if (!name || !*name) { notify(player, T("You need to specify a channel.")); return; @@ -3651,7 +3624,8 @@ do_chan_buffer(dbref player, const char *name, const char *lines) free_bufferq(ChanBufferQ(chan)); ChanBufferQ(chan) = NULL; notify_format(player, - T("CHAT: Channel buffering disabled for channel <%s>."), + T + ("CHAT: Channel buffering disabled for channel <%s>."), ChanName(chan)); } else { notify_format(player, @@ -3663,8 +3637,8 @@ do_chan_buffer(dbref player, const char *name, const char *lines) if (ChanBufferQ(chan)) { /* Resize a buffer */ ChanBufferQ(chan) = reallocate_bufferq(ChanBufferQ(chan), size); - notify_format(player, T("CHAT: Resizing buffer of channel <%s>"), - ChanName(chan)); + notify_format(player, + T("CHAT: Resizing buffer of channel <%s>"), ChanName(chan)); } else { /* Start a new buffer */ ChanBufferQ(chan) = allocate_bufferq(size); @@ -3678,156 +3652,31 @@ do_chan_buffer(dbref player, const char *name, const char *lines) /* 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); - + else if (u && CUtitle(u)) + title = CUtitle(u); if (Channel_NoNames(chan)) { - if (Channel_NoTitles(chan) || !title) - channel_broadcast(chan, victim, flags, msg, ChanObjName(chan), "Someone"); - else - channel_broadcast(chan, victim, flags, msg, ChanObjName(chan), title); - } else - channel_broadcast(chan, victim, flags, msg, ChanObjName(chan), Name(victim)); -} - - -static void -do_reset_cobj(player, name) - dbref player; - const char *name; -{ - CHAN *c; - /* Test Channel */ - test_channel(player, name, c); - if(!Chan_Can_Modify(c, player)) { - notify(player, "CHAT: Oh come on."); - return; + 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); } - /* Now lets reset teh chan obj stuff on the channel */ - ChanType(c) &= ~CHANNEL_COBJ; - ChanObj(c) = -1; - notify(player,"ChanObj Reset."); -} - - -static void -do_set_cobj(player, name, obj) - dbref player; - const char *name; - const char *obj; -{ - CHAN *c; - dbref cobj; - /* Test the channel */ - test_channel(player, name, c); - - if(!Chan_Can_Modify(c, player)) { - notify(player, "CHAT: Oh come on."); - return; - } - - /* Not sure if all this shit works right, so be careful */ - - cobj = match_result(player, obj, TYPE_THING, MAT_ABSOLUTE); - - if(cobj == -1) { - notify(player, "Invalid Object"); - return; - } - - - if(cobj == -2) { - notify(player, "Ambigious Object"); - return; - } - - if(!controls(player,cobj)) { - notify(player,"You must own that object first"); - return; - } - - if(Typeof(cobj) != TYPE_THING) { - notify(player, "Must be an object"); - return; - } - - ChanType(c) |= CHANNEL_COBJ; - ChanObj(c) = cobj; - - notify(player,tprintf("Channel object for %s is now #%ld", ChanName(c), - ChanObj(c)) ); - -} - -int ChanObjCheck(CHAN *c) - { - if(ChanType(c) & CHANNEL_COBJ) { - if(Typeof(ChanObj(c)) == TYPE_GARBAGE) { - ChanType(c) &= ~CHANNEL_COBJ; - ChanObj(c) = -1; - return 0; - } else return 1; - } else return 0; -} - -const char * -ChanObjName(CHAN *c) - { - ATTR *nm; - static char buff[BUFFER_LEN]; - static char tbuf[BUFFER_LEN]; - - if(!c) - return NULL; - - if(ChanType(c) & CHANNEL_COBJ) { - if(Typeof(ChanObj(c)) == TYPE_GARBAGE) { - ChanType(c) &= ~(CHANNEL_COBJ); - ChanObj(c) = -1; - strcpy(buff,tprintf("<%s>", ChanName(c))); - return buff; - } - - nm = atr_get_noparent(ChanObj(c), "CHANNAME"); - if(nm) { - strcpy(tbuf,atr_value(nm)); - strcpy(buff,(char *) nv_eval(ChanObj(c), tbuf)); - } - else { - strcpy(buff,tprintf("<%s>", ChanName(c))); - } - } - else { - strcpy(buff,tprintf("<%s>", ChanName(c))); } - - return buff; -} - -static char *nv_eval(dbref thing, const char *code) { - static char my_buff[BUFFER_LEN * 3]; - char *my_bp = my_buff; - char *tbuf = (char *) mush_malloc(BUFFER_LEN, "nv_eval"); - char *tbuf_ptr = tbuf; - - strcpy(tbuf, code); - process_expression(my_buff, &my_bp, (const char **) &tbuf, - thing, thing, thing, PE_DEFAULT, PT_DEFAULT, - (PE_Info *) NULL); - - *my_bp = '\0'; - - mush_free((Malloc_t) tbuf_ptr, "nv_eval"); - return my_buff; + } else { + snprintf(fmtbuff, BUFFER_LEN, msg, Name(victim)); + } + channel_chat(chan, victim, flags, fmtbuff, '@', "<%s> %s", + ChanName(chan), fmtbuff); } -/* Evaluate a channel lock with %0 set to the channel name. +/** Evaluate a channel lock with %0 set to the channel name. * \param c the channel to test. * \param p the object trying to pass the lock. * \param type the type of channel lock to test. @@ -3839,10 +3688,8 @@ eval_chan_lock(CHAN *c, dbref p, enum clock_type type) char *oldenv[10]; boolexp b = TRUE_BOOLEXP; int retval, n; - if (!c || !GoodObject(p)) return 0; - switch (type) { case CLOCK_SEE: b = ChanSeeLock(c); @@ -3864,11 +3711,8 @@ eval_chan_lock(CHAN *c, dbref p, enum clock_type type) global_eval_context.wenv[0] = ChanName(c); for (n = 1; n < 10; n++) global_eval_context.wenv[n] = NULL; - retval = eval_boolexp(p, b, p, NULL); + retval = eval_boolexp(p, b, p); restore_global_env("eval_chan_lock", oldenv); - return retval; - } - #endif /* CHAT_SYSTEM */ diff --git a/src/extmail.c b/src/extmail.c index 9e97eb3..477ed15 100644 --- a/src/extmail.c +++ b/src/extmail.c @@ -62,6 +62,9 @@ #ifdef I_SYS_TIME #include +#ifdef TIME_WITH_SYS_TIME +#include +#endif #else #include #endif @@ -70,6 +73,9 @@ #include #endif #include +#ifdef HAVE_STDINT_H +#include +#endif #include "conf.h" #include "externs.h" @@ -81,6 +87,7 @@ #include "attrib.h" #include "parse.h" #include "mymalloc.h" +#include "ansi.h" #include "pueblo.h" #include "flags.h" #include "log.h" @@ -94,8 +101,8 @@ extern int do_convtime(const char *str, struct tm *ttm); /* funtime.c */ static void do_mail_flags - (dbref player, const char *msglist, mail_flag flag, int negate); -static char *mail_list_time(const char *the_time, int flag); + (dbref player, const char *msglist, mail_flag flag, bool negate); +static char *mail_list_time(const char *the_time, bool flag); static MAIL *mail_fetch(dbref player, int num); static MAIL *real_mail_fetch(dbref player, int num, int folder); static MAIL *mailfun_fetch(dbref player, int nargs, char *arg1, char *arg2); @@ -135,6 +142,8 @@ static int was_sender(dbref player, MAIL *mp); MAIL *maildb; /**< The head of the mail list */ MAIL *tail_ptr; /**< The end of the mail list */ +slab *mail_slab; /**< slab for 'struct mail' allocations */ + #define HEAD maildb /**< The head of the mail list */ #define TAIL tail_ptr /**< The end of the mail list */ @@ -282,7 +291,7 @@ do_mail_change_folder(dbref player, char *fld, char *newname) return; } for (p = newname; p && *p; p++) { - if (!isdigit((unsigned char) *p) && !isalpha((unsigned char) *p)) { + if (!isalnum((unsigned char) *p)) { notify(player, T("MAIL: Illegal folder name")); return; } @@ -372,11 +381,12 @@ do_mail_unclear(dbref player, const char *msglist) * \param negate if 1, clear the flag; if 0, set the flag. */ static void -do_mail_flags(dbref player, const char *msglist, mail_flag flag, int negate) +do_mail_flags(dbref player, const char *msglist, mail_flag flag, bool negate) { MAIL *mp; struct mail_selector ms; - int j, folder; + int j; + mail_flag folder; folder_array i; int notified = 0; @@ -458,7 +468,8 @@ do_mail_file(dbref player, char *msglist, char *folder) { MAIL *mp; struct mail_selector ms; - int j, foldernum, origfold; + int j, foldernum; + mail_flag origfold; folder_array i; int notified = 0; @@ -515,7 +526,8 @@ do_mail_read(dbref player, char *msglist) char tbuf1[BUFFER_LEN]; char folderheader[BUFFER_LEN]; struct mail_selector ms; - int j, folder; + int j; + mail_flag folder; folder_array i; if (!parse_msglist(msglist, &ms, player)) { @@ -532,15 +544,15 @@ do_mail_read(dbref player, char *msglist) /* Read it */ j++; if (SUPPORT_PUEBLO) { - notify_noenter(player, tprintf("%cSAMP%c", TAG_START, TAG_END)); - sprintf(folderheader, - "%cA XCH_HINT=\"List messages in this folder\" XCH_CMD=\"@mail/list %d:1-\"%c%s%c/A%c", - TAG_START, Folder(mp), TAG_END, T("Folder:"), TAG_START, - TAG_END); + notify_noenter(player, open_tag("SAMP")); + snprintf(folderheader, BUFFER_LEN, + "%c%cA XCH_HINT=\"List messages in this folder\" XCH_CMD=\"@mail/list %d:1-\"%c%s%c%c/A%c", + TAG_START, MARKUP_HTML, Folder(mp), TAG_END, T("Folder:"), + TAG_START, MARKUP_HTML, TAG_END); } else - strcpy(folderheader, T("Folder:")); + mush_strncpy(folderheader, T("Folder:"), BUFFER_LEN); notify(player, DASH_LINE); - strcpy(tbuf1, get_sender(mp, 1)); + mush_strncpy(tbuf1, get_sender(mp, 1), BUFFER_LEN); notify_format(player, T ("From: %-55s %s\nDate: %-25s %s %2d Message: %d\nStatus: %s"), @@ -553,12 +565,11 @@ do_mail_read(dbref player, char *msglist) notify_format(player, T("Subject: %s"), get_subject(mp)); notify(player, DASH_LINE); if (SUPPORT_PUEBLO) - notify_noenter(player, tprintf("%c/SAMP%c", TAG_START, TAG_END)); + notify_noenter(player, close_tag("SAMP")); strcpy(tbuf1, get_message(mp)); notify(player, tbuf1); if (SUPPORT_PUEBLO) - notify_format(player, "%cSAMP%c%s%c/SAMP%c", TAG_START, TAG_END, - DASH_LINE, TAG_START, TAG_END); + notify(player, wrap_tag("SAMP", DASH_LINE)); else notify(player, DASH_LINE); if (Unread(mp)) @@ -586,7 +597,8 @@ do_mail_list(dbref player, const char *msglist) char sender[30]; MAIL *mp; struct mail_selector ms; - int j, folder; + int j; + mail_flag folder; folder_array i; if (!parse_msglist(msglist, &ms, player)) { @@ -596,7 +608,7 @@ do_mail_list(dbref player, const char *msglist) j = 0; folder = MSFolder(ms) ? MSFolder(ms) : player_folder(player); if (SUPPORT_PUEBLO) - notify_noenter(player, tprintf("%cSAMP%c", TAG_START, TAG_END)); + notify_noenter(player, open_tag("SAMP")); notify_format(player, T ("--------------------------- MAIL (folder %2d) ------------------------------"), @@ -610,8 +622,8 @@ do_mail_list(dbref player, const char *msglist) if (SUPPORT_PUEBLO) notify_noenter(player, tprintf - ("%cA XCH_CMD=\"@mail/read %d:%d\" XCH_HINT=\"Read message %d in folder %d\"%c", - TAG_START, Folder(mp), i[Folder(mp)], + ("%c%cA XCH_CMD=\"@mail/read %d:%d\" XCH_HINT=\"Read message %d in folder %d\"%c", + TAG_START, MARKUP_HTML, Folder(mp), i[Folder(mp)], i[Folder(mp)], Folder(mp), TAG_END)); strcpy(subj, chopstr(get_subject(mp), 28)); strcpy(sender, chopstr(get_sender(mp, 0), 12)); @@ -623,18 +635,19 @@ do_mail_list(dbref player, const char *msglist) ? '*' : ' '), sender, 30, subj, mail_list_time(show_time(mp->time, 0), 1)); if (SUPPORT_PUEBLO) - notify_noenter(player, tprintf("%c/A%c", TAG_START, TAG_END)); + notify_noenter(player, tprintf("%c%c/A%c", TAG_START, + MARKUP_HTML, TAG_END)); } } } notify(player, DASH_LINE); if (SUPPORT_PUEBLO) - notify_format(player, "%c/SAMP%c", TAG_START, TAG_END); + notify(player, close_tag("SAMP")); return; } static char * -mail_list_time(const char *the_time, int flag /* 1 for no year */ ) +mail_list_time(const char *the_time, bool flag /* 1 for no year */ ) { static char newtime[BUFFER_LEN]; const char *p; @@ -697,16 +710,12 @@ do_mail_purge(dbref player) mdb_top--; free(mp->subject); chunk_delete(mp->msgid); - mush_free((Malloc_t) mp, "mail"); + slab_free(mail_slab, mp); } else { nextp = mp->next; } } - /* Clean up the player's mailp */ - if (Connected(player)) { - desc_mail_set(player, NULL); - desc_mail_set(player, find_exact_starting_point(player)); - } + set_objdata(player, "MAIL", NULL); notify(player, T("MAIL: Mailbox purged.")); return; } @@ -725,7 +734,8 @@ do_mail_fwd(dbref player, char *msglist, char *tolist) MAIL *mp; MAIL *last; struct mail_selector ms; - int j, num, folder; + int j, num; + mail_flag folder; folder_array i; const char *head; MAIL *temp; @@ -774,8 +784,8 @@ do_mail_fwd(dbref player, char *msglist, char *tolist) } else { char tbuf1[BUFFER_LEN]; unsigned char tbuf2[BUFFER_LEN]; - strcpy(tbuf1, uncompress(mp->subject)); - u_strcpy(tbuf2, get_compressed_message(mp)); + mush_strncpy(tbuf1, uncompress(mp->subject), BUFFER_LEN); + u_strncpy(tbuf2, get_compressed_message(mp), BUFFER_LEN); send_mail(player, temp->from, tbuf1, (char *) tbuf2, M_FORWARD | M_REPLY, 1, 0); num_recpts++; @@ -794,8 +804,8 @@ do_mail_fwd(dbref player, char *msglist, char *tolist) } else { char tbuf1[BUFFER_LEN]; unsigned char tbuf2[BUFFER_LEN]; - strcpy(tbuf1, uncompress(mp->subject)); - u_strcpy(tbuf2, get_compressed_message(mp)); + mush_strncpy(tbuf1, uncompress(mp->subject), BUFFER_LEN); + u_strncpy(tbuf2, get_compressed_message(mp), BUFFER_LEN); send_mail(player, target, tbuf1, (char *) tbuf2, M_FORWARD, 1, 0); num_recpts++; } @@ -823,7 +833,7 @@ do_mail_send(dbref player, char *tolist, char *message, mail_flag flags, const char *head; int num; dbref target; - int mail_flags; + mail_flag mail_flags; char sbuf[SUBJECT_LEN + 1], *sb, *mb; int i = 0, subject_given = 0; const char **start; @@ -922,7 +932,8 @@ real_mail_fetch(dbref player, int num, int folder) for (mp = find_exact_starting_point(player); mp != NULL; mp = mp->next) { if (mp->to > player) break; - if ((mp->to == player) && ((folder < 0) || (Folder(mp) == folder))) + if ((mp->to == player) && ((folder < 0) + || (Folder(mp) == (mail_flag) folder))) i++; if (i == num) return mp; @@ -943,7 +954,8 @@ count_mail(dbref player, int folder, int *rcount, int *ucount, int *ccount) cc = rc = uc = 0; for (mp = find_exact_starting_point(player); mp && (mp->to == player); mp = mp->next) { - if ((mp->to == player) && ((folder == -1) || (Folder(mp) == folder))) { + if ((mp->to == player) && ((folder == -1) || + (Folder(mp) == (mail_flag) folder))) { if (Cleared(mp)) cc++; else if (Read(mp)) @@ -1043,8 +1055,14 @@ real_send_mail(dbref player, dbref target, char *subject, char *message, return 0; } + /* Where do we insert it? After mp, wherever that is. + * This can return NULL if there are no messages or + * if we insert at the head of the list + */ + mp = find_insertion_point(target); + /* initialize the appropriate fields */ - newp = (MAIL *) mush_malloc(sizeof(struct mail), "mail"); + newp = slab_malloc(mail_slab, mp); newp->to = target; newp->from = player; newp->from_ctime = CreTime(player); @@ -1064,10 +1082,10 @@ real_send_mail(dbref player, dbref target, char *subject, char *message, newp->subject = compress(sbuf); if (flags & M_FORWARD) { /* Forwarding passes the message already compressed */ - int len = strlen(message) + 1; + size_t len = strlen(message) + 1; newp->msgid = chunk_create((unsigned char *) message, len, 1); } else { - int len; + uint16_t len; unsigned char *text; newmsg = (char *) mush_malloc(BUFFER_LEN, "string"); if (!newmsg) @@ -1086,25 +1104,19 @@ real_send_mail(dbref player, dbref target, char *subject, char *message, *bp = '\0'; free(mailsig); safe_str(buff, newmsg, &nm); - mush_free((Malloc_t) buff, "string"); + mush_free(buff, "string"); } *nm = '\0'; text = compress(newmsg); len = u_strlen(text) + 1; newp->msgid = chunk_create(text, len, 1); free(text); - mush_free((Malloc_t) newmsg, "string"); + mush_free(newmsg, "string"); } newp->time = mudtime; newp->read = flags & M_FMASK; /* Send to folder 0 */ - /* Where do we insert it? After mp, wherever that is. - * This can return NULL if there are no messages or - * if we insert at the head of the list - */ - mp = find_insertion_point(target); - if (mp) { newp->prev = mp; newp->next = mp->next; @@ -1129,12 +1141,6 @@ real_send_mail(dbref player, dbref target, char *subject, char *message, } } - /* If the target's mailp isn't pointing to their list, we'd better - * set it - */ - if (Connected(target)) - desc_mail_set(target, find_exact_starting_point(target)); - mdb_top++; /* notify people */ @@ -1174,12 +1180,11 @@ do_mail_nuke(dbref player) if (mp->subject) free(mp->subject); chunk_delete(mp->msgid); - mush_free((Malloc_t) mp, "mail"); + slab_free(mail_slab, mp); } HEAD = TAIL = NULL; mdb_top = 0; - desc_mail_clear(); do_log(LT_ERR, 0, 0, T("** MAIL PURGE ** done by %s(#%d)."), Name(player), player); @@ -1258,7 +1263,7 @@ do_mail_debug(dbref player, const char *action, const char *victim) if (mp->subject) free(mp->subject); chunk_delete(mp->msgid); - mush_free((Malloc_t) mp, "mail"); + slab_free(mail_slab, mp); } else if (!GoodObject(mp->from)) { /* Oops, it's from a player whose dbref is out of range! * We'll make it appear to be from #0 instead because there's @@ -1939,11 +1944,10 @@ find_exact_starting_point(dbref player) if (!HEAD) return NULL; - mp = desc_mail(player); + + mp = get_objdata(player, "MAIL"); if (!mp) { - /* Player is connected and has no mail, or nobody's connected who - * has mail - we have to scan the maildb. - */ + /* Player hasn't already done something that looks up their mail. */ if (HEAD->to > player) return NULL; /* No mail chain */ for (mp = HEAD; mp && (mp->to < player); mp = mp->next) ; @@ -1955,9 +1959,11 @@ find_exact_starting_point(dbref player) while (mp && (mp->to < player)) mp = mp->next; } - if (mp && (mp->to == player)) + if (mp && (mp->to == player)) { + set_objdata(player, "MAIL", mp); return mp; - return NULL; + } else + return NULL; } @@ -1973,11 +1979,8 @@ find_insertion_point(dbref player) if (!HEAD) return NULL; - mp = desc_mail(player); + mp = get_objdata(player, "MAIL"); if (!mp) { - /* Player is connected and has no mail, or nobody's connected who - * has mail - we have to scan the maildb. - */ if (HEAD->to > player) return NULL; /* No mail chain */ for (mp = TAIL; mp && (mp->to > player); mp = mp->prev) ; @@ -1997,9 +2000,15 @@ find_insertion_point(dbref player) void mail_init(void) { - mdb_top = 0; - HEAD = NULL; - TAIL = NULL; + static bool init_called = 0; + if (!init_called) { + init_called = 1; + mdb_top = 0; + mail_slab = slab_create("mail messages", sizeof(struct mail)); + slab_set_opt(mail_slab, SLAB_HINTLESS_THRESHOLD, 5); + HEAD = NULL; + TAIL = NULL; + } } /** Load mail from disk. @@ -2011,7 +2020,7 @@ load_mail(FILE * fp) char nbuf1[8]; unsigned char *tbuf = NULL; unsigned char *text; - int len; + size_t len; int mail_top = 0; int mail_flags = 0; int i = 0; @@ -2036,8 +2045,7 @@ load_mail(FILE * fp) /* mail_top could be 0 from an error or actually be 0. */ if (nbuf1[0] == '0' && nbuf1[1] == '\n') { char buff[20]; - fgets(buff, sizeof buff, fp); - if (!*buff) + if (!fgets(buff, sizeof buff, fp)) do_rawlog(LT_ERR, T("MAIL: Missing end-of-dump marker in mail database.")); else if (strcmp(buff, (mail_flags & MDBF_NEW_EOD) @@ -2049,11 +2057,11 @@ load_mail(FILE * fp) return 0; } /* first one is a special case */ - mp = (MAIL *) mush_malloc(sizeof(struct mail), "mail"); + mp = slab_malloc(mail_slab, NULL); mp->to = getref(fp); mp->from = getref(fp); if (mail_flags & MDBF_SENDERCTIME) - mp->from_ctime = getref(fp); + mp->from_ctime = (time_t) getref(fp); else mp->from_ctime = 0; /* No one will have this creation time */ @@ -2084,11 +2092,11 @@ load_mail(FILE * fp) /* now loop through */ for (; i < mail_top; i++) { - mp = (MAIL *) mush_malloc(sizeof(struct mail), "mail"); + mp = slab_malloc(mail_slab, NULL); mp->to = getref(fp); mp->from = getref(fp); if (mail_flags & MDBF_SENDERCTIME) - mp->from_ctime = getref(fp); + mp->from_ctime = (time_t) getref(fp); else mp->from_ctime = 0; /* No one will have this creation time */ if (do_convtime(getstring_noalloc(fp), &ttm)) @@ -2106,10 +2114,10 @@ load_mail(FILE * fp) if (tbuf) mp->subject = tbuf; else { - strcpy(sbuf, get_message(mp)); + mush_strncpy(sbuf, get_message(mp), BUFFER_LEN); mp->subject = compress(chopstr(sbuf, SUBJECT_LEN)); } - mp->read = getref(fp); + mp->read = (uint32_t) getref(fp); /* We now to a sorted insertion, sorted by recipient db# */ if (mp->to >= TAIL->to) { @@ -2152,8 +2160,7 @@ load_mail(FILE * fp) } { char buff[20]; - fgets(buff, sizeof buff, fp); - if (!*buff) + if (!fgets(buff, sizeof buff, fp)) do_rawlog(LT_ERR, T("MAIL: Missing end-of-dump marker in mail database.")); else if (strcmp(buff, (mail_flags & MDBF_NEW_EOD) @@ -2163,7 +2170,8 @@ load_mail(FILE * fp) } do_mail_debug(GOD, "fix", ""); - return (mdb_top); + slab_set_opt(mail_slab, SLAB_ALLOC_BEST_FIT, 1); + return mdb_top; } static int @@ -2175,8 +2183,8 @@ get_folder_number(dbref player, char *name) a = (ATTR *) atr_get_noparent(player, "MAILFOLDERS"); if (!a) return -1; - strcpy(str, atr_value(a)); - sprintf(pat, ":%s:", strupper(name)); + mush_strncpy(str, atr_value(a), BUFFER_LEN); + snprintf(pat, BUFFER_LEN, ":%s:", strupper(name)); res = strstr(str, pat); if (!res) return -1; @@ -2243,7 +2251,7 @@ add_folder_name(dbref player, int fld, const char *name) mush_panic(T("Failed to allocate strings in add_folder_name")); if (name && *name) - sprintf(new, "%d:%s:%d ", fld, strupper(name), fld); + snprintf(new, BUFFER_LEN, "%d:%s:%d ", fld, strupper(name), fld); else strcpy(new, " "); sprintf(pat, "%d:", fld); @@ -2255,7 +2263,7 @@ add_folder_name(dbref player, int fld, const char *name) old = (char *) string_match(str, pat); } if (old && *old) { - strcpy(tbuf, str); + mush_strncpy(tbuf, str, BUFFER_LEN); r = old; while (!isspace((unsigned char) *r)) r++; @@ -2346,7 +2354,7 @@ mail_match(dbref player, MAIL *mp, struct mail_selector ms, int num) return 0; if (ms.player && !was_sender(ms.player, mp)) return 0; - if (AllInFolder(ms) && (Folder(mp) == player_folder(player))) + if (AllInFolder(ms) && (Folder(mp) == (mail_flag) player_folder(player))) return 1; mpflag = Read(mp) ? mp->read : (mp->read | M_MSUNREAD); if (!All(ms) && !(ms.flags & mpflag)) @@ -2632,7 +2640,7 @@ parse_message_spec(dbref player, const char *s, int *msglow, int *msghigh, /* f: */ *msglow = 0; if (msghigh) - *msghigh = HUGE_INT; + *msghigh = INT_MAX; } else { if (!is_integer(p)) return 0; diff --git a/src/flags.c b/src/flags.c index e636823..1a5e9c4 100644 --- a/src/flags.c +++ b/src/flags.c @@ -21,6 +21,9 @@ #ifdef I_SYS_TIME #include +#ifdef TIME_WITH_SYS_TIME +#include +#endif #else #include #endif @@ -44,6 +47,8 @@ #include "lock.h" #include "log.h" #include "dbio.h" +#include "sort.h" +#include "mymalloc.h" #include "oldflags.h" #include "division.h" #include "ansi.h" @@ -71,6 +76,7 @@ static void flag_fake_read(FILE *); PTAB ptab_flag; /**< Table of flags by name, inc. aliases */ HASHTAB htab_flagspaces; /**< Hash of flagspaces */ +slab *flag_slab = NULL; extern PTAB ptab_command; /* Uses flag bitmasks */ extern long flagdb_flags; @@ -244,7 +250,7 @@ match_flag(const char *name) * \return poiner to flag structure, or NULL. */ static FLAG * -match_flag_ns(FLAGSPACE * n, const char *name) +match_flag_ns(FLAGSPACE *n, const char *name) { return (FLAG *) ptab_find(n->tab, name); } @@ -260,7 +266,7 @@ match_flag_ns(FLAGSPACE * n, const char *name) * \return pointer to flag structure, or NULL. */ static FLAG * -flag_hash_lookup(FLAGSPACE * n, const char *name, int type) +flag_hash_lookup(FLAGSPACE *n, const char *name, int type) { FLAG *f; @@ -291,7 +297,11 @@ flag_hash_lookup(FLAGSPACE * n, const char *name, int type) static FLAG * new_flag(void) { - FLAG *f = (FLAG *) mush_malloc(sizeof(FLAG), "flag"); + FLAG *f; + + if (flag_slab == NULL) + flag_slab = slab_create("flags", sizeof(FLAG)); + f = slab_malloc(flag_slab, NULL); if (!f) mush_panic("Unable to allocate memory for a new flag!\n"); return f; @@ -299,7 +309,7 @@ new_flag(void) /* Deallocate all flag-related memory */ static void -clear_all_flags(FLAGSPACE * n) +clear_all_flags(FLAGSPACE *n) { FLAG *f; @@ -307,23 +317,25 @@ clear_all_flags(FLAGSPACE * n) f->perms = DECR_FLAG_REF(f->perms); if (FLAG_REF(f->perms) == 0) { mush_free((void *) f->name, "flag.name"); - mush_free(f, "flag"); + slab_free(flag_slab, f); } } ptab_free(n->tab); + /* Finally, the flags array */ if (n->flags) mush_free(n->flags, "flagspace.flags"); n->flags = NULL; n->flagbits = 0; + } static FLAG * clone_flag(FLAG *f) { FLAG *clone = new_flag(); - clone->name = mush_strdup(f->name, "flag name"); + clone->name = mush_strdup(f->name, "flag.name"); clone->letter = f->letter; clone->type = f->type; clone->bitpos = f->bitpos; @@ -339,7 +351,7 @@ clone_flag(FLAG *f) * f->bitpos is used. */ static void -flag_add(FLAGSPACE * n, const char *name, FLAG *f) +flag_add(FLAGSPACE *n, const char *name, FLAG *f) { /* If this flag has no bitpos assigned, assign it the next one. * We could improve this algorithm to use the next available @@ -356,9 +368,7 @@ flag_add(FLAGSPACE * n, const char *name, FLAG *f) f->perms = INCR_FLAG_REF(f->perms); /* Insert the flag in the ptab by the given name (maybe an alias) */ - ptab_start_inserts(n->tab); - ptab_insert(n->tab, name, f); - ptab_end_inserts(n->tab); + ptab_insert_one(n->tab, name, f); /* Is this a canonical flag (as opposed to an alias?) * If it's an alias, we're done. @@ -372,13 +382,12 @@ flag_add(FLAGSPACE * n, const char *name, FLAG *f) int i; if (f->bitpos >= n->flagbits) { /* Oops, we need a bigger array */ - if (n->flagbits == 0) - n->flags = mush_malloc(sizeof(FLAG *), "flagspace.flags"); - else { - n->flags = realloc(n->flags, (f->bitpos + 1) * sizeof(FLAG *)); - if (!n->flags) - mush_panic("Unable to reallocate flags array!\n"); - } + n->flags = + mush_realloc(n->flags, (f->bitpos + 1) * sizeof(FLAG *), + "flagspace.flags"); + if (!n->flags) + mush_panic("Unable to reallocate flags array!\n"); + /* Make sure the new space is full of NULLs */ for (i = n->flagbits; i <= f->bitpos; i++) n->flags[i] = NULL; @@ -420,9 +429,9 @@ flag_read_oldstyle(FILE * in) { FLAG *f; char *c; - c = mush_strdup(getstring_noalloc(in), "flag name"); + c = mush_strdup(getstring_noalloc(in), "flag.name"); if (!strcmp(c, "FLAG ALIASES")) { - mush_free(c, "flag name"); + mush_free(c, "flag.name"); return NULL; /* We're done */ } f = new_flag(); @@ -507,7 +516,7 @@ flag_read(FILE * in) char *tmp; db_read_this_labeled_string(in, "name", &tmp); - c = mush_strdup(tmp, "flag name"); + c = mush_strdup(tmp, "flag.name"); f = new_flag(); f->name = c; db_read_this_labeled_string(in, "letter", &tmp); @@ -530,7 +539,7 @@ flag_read(FILE * in) } static FLAG * -flag_alias_read(FILE * in, char *alias, FLAGSPACE * n) +flag_alias_read(FILE * in, char *alias, FLAGSPACE *n) { FLAG *f; char *c; @@ -591,7 +600,7 @@ flag_read_all(FILE * in, const char *ns) /* If we are reading flags from the db, they are definitive. */ clear_all_flags(n); - db_read_this_labeled_number(in, "flagcount", &count); + db_read_this_labeled_int(in, "flagcount", &count); for (;;) { int c; @@ -613,7 +622,7 @@ flag_read_all(FILE * in, const char *ns) found, count); /* Assumes we'll always have at least one alias */ - db_read_this_labeled_number(in, "flagaliascount", &count); + db_read_this_labeled_int(in, "flagaliascount", &count); for (found = 0 ;;) { int c; @@ -641,7 +650,7 @@ static void flag_fake_read(FILE *f) { int count; /* Read shit into NULL-ville */ - db_read_this_labeled_number(f, "flagcount", &count); + db_read_this_labeled_int(f, "flagcount", &count); for(; count > 0; count--) { getstring_noalloc(f); @@ -651,7 +660,7 @@ static void flag_fake_read(FILE *f) { getstring_noalloc(f); } - db_read_this_labeled_number(f, "flagaliascount", &count); + db_read_this_labeled_int(f, "flagaliascount", &count); for(; count > 0; count--) { getstring_noalloc(f); getstring_noalloc(f); @@ -703,7 +712,7 @@ flag_write_all(FILE * out, const char *ns) if (n->flags[i]) count++; } - db_write_labeled_number(out, "flagcount", count); + db_write_labeled_int(out, "flagcount", count); for (i = 0; i < n->flagbits; i++) { if (n->flags[i]) flag_write(out, n->flags[i], n->flags[i]->name); @@ -719,7 +728,7 @@ flag_write_all(FILE * out, const char *ns) count++; f = ptab_nextentry_new(n->tab, flagname); } - db_write_labeled_number(out, "flagaliascount", count); + db_write_labeled_int(out, "flagaliascount", count); f = ptab_firstentry_new(n->tab, flagname); while (f) { if (strcmp(n->flags[f->bitpos]->name, flagname)) { @@ -737,9 +746,10 @@ init_flagspaces(void) { FLAGSPACE *flags; - hashinit(&htab_flagspaces, 4, sizeof(FLAGSPACE)); + hashinit(&htab_flagspaces, 4); flags = (FLAGSPACE *) mush_malloc(sizeof(FLAGSPACE), "flagspace"); flags->tab = &ptab_flag; + ptab_init(&ptab_flag); flags->flagbits = 0; flags->flags = NULL; flags->flag_table = flag_table; @@ -767,13 +777,14 @@ init_flag_table(const char *ns) do_rawlog(LT_ERR, T("Initializing flag table.")); - ptab_init(n->tab); + ptab_start_inserts(n->tab); /* do regular flags first */ for (f = n->flag_table; f->name; f++) { cf = clone_flag(f); cf->bitpos = -1; flag_add(n, cf->name, cf); } + ptab_end_inserts(n->tab); /* now add in the aliases */ for (a = n->flag_alias_table; a->alias; a++) { if ((f = match_flag_ns(n, a->realname))) @@ -911,7 +922,7 @@ flags_from_old_flags(long old_flags, long old_toggles, int type) /* Given a single character, return the matching flag definition */ static FLAG * -letter_to_flagptr(FLAGSPACE * n, char c, int type) +letter_to_flagptr(FLAGSPACE *n, char c, int type) { FLAG *f; int i; @@ -953,7 +964,7 @@ new_flag_bitmask(const char *ns) object_flag_type bitmask; FLAGSPACE *n; Flagspace_Lookup(n, ns); - bitmask = (object_flag_type) mush_malloc(FlagBytes(n), "flag_bitmask"); + bitmask = mush_malloc(FlagBytes(n), "flag_bitmask"); if (!bitmask) mush_panic("Unable to allocate memory for flag bitmask"); memset(bitmask, 0, FlagBytes(n)); @@ -1203,7 +1214,7 @@ string_to_bits(const char *ns, const char *str) * \param thing object to check. * \param flag name of flag to check for (a string). * \param type allowed types of flags to check for. - * \retval 1 object has the flag. + * \retval >0 object has the flag. * \retval 0 object does not have the flag. */ int @@ -1993,7 +2004,7 @@ add_flag(const char *name, const char letter, int type, return f; } f = new_flag(); - f->name = mush_strdup(strupper(name), "flag name"); + f->name = mush_strdup(strupper(name), "flag.name"); f->letter = letter; f->type = type; f->perms = perms; @@ -2386,9 +2397,8 @@ alias_flag_generic(const char *ns, const char *name, const char *alias) f->perms = INCR_FLAG_REF(f->perms); - ptab_start_inserts(n->tab); - ptab_insert(n->tab, strupper(alias), f); - ptab_end_inserts(n->tab); + ptab_insert_one(n->tab, strupper(alias), f); + return ((f = match_flag_ns(n, alias)) ? 1 : 0); } @@ -2528,8 +2538,8 @@ do_flag_delete(dbref player, const char *name) ptab_delete(n->tab, f->name); notify_format(player, T("Flag %s deleted."), f->name); /* Free the flag. */ - mush_free((char *) f->name, "flag name"); - mush_free(f, "flag"); + mush_free((void *) f->name, "flag.name"); + slab_free(flag_slab, f); } /** Enable a disabled flag. @@ -2564,7 +2574,7 @@ do_flag_enable(dbref player, const char *name) static char * -list_aliases(FLAGSPACE * n, FLAG *given) +list_aliases(FLAGSPACE *n, FLAG *given) { FLAG *f; static char buf[BUFFER_LEN]; diff --git a/src/funcrypt.c b/src/funcrypt.c index ba59b5e..8003953 100644 --- a/src/funcrypt.c +++ b/src/funcrypt.c @@ -15,7 +15,9 @@ #include "case.h" #include "externs.h" #include "version.h" +#ifdef CHAT_SYSTEM #include "extchat.h" +#endif #include "htab.h" #include "flags.h" #include "dbdefs.h" @@ -29,19 +31,161 @@ #ifdef HAS_OPENSSL #include #include +#include #else #include "shs.h" #endif #include "confmagic.h" -static char *crunch_code _((char *code)); -static char *crypt_code _((char *code, char *text, int type)); +static char *crunch_code(char *code); +static char *crypt_code(char *code, char *text, int type); -#ifdef HAS_OPENSSL +static void safe_sha0(const char *text, size_t len, char *buff, char **bp); static void safe_hexchar(unsigned char c, char *buff, char **bp); + +static bool +encode_base64 +#ifdef HAVE_SSL +(const char *input, int len, char *buff, char **bp) +{ + BIO *bio, *b64, *bmem; + char *membuf; + + b64 = BIO_new(BIO_f_base64()); + if (!b64) { + safe_str(T("#-1 ALLOCATION ERROR"), buff, bp); + return false; + } + + BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); + + bmem = BIO_new(BIO_s_mem()); + if (!bmem) { + safe_str(T("#-1 ALLOCATION ERROR"), buff, bp); + BIO_free(b64); + return false; + } + + bio = BIO_push(b64, bmem); + + if (BIO_write(bio, input, len) < 0) { + safe_str(T("#-1 CONVERSION ERROR"), buff, bp); + BIO_free_all(bio); + return false; + } + + len = BIO_flush(bio); + + len = BIO_get_mem_data(bmem, &membuf); + + safe_strl(membuf, len, buff, bp); + + BIO_free_all(bio); + + return true; +#else + (const char *input __attribute__ ((__unused__)), int len __attribute__ ((__unused__)), char *buff, char **bp) + { + safe_str(T("#-1 FUNCTION DISABLED"), buff, bp); + return false; +#endif +} + +static void safe_sha0(const char *text, size_t len, char *buff, char **bp); +extern char valid_ansi_codes[UCHAR_MAX + 1]; + +static bool +#ifdef HAVE_SSL +decode_base64(char *encoded, int len, char *buff, char **bp) +{ + BIO *bio, *b64, *bmem; + char *sbp; + + b64 = BIO_new(BIO_f_base64()); + if (!b64) { + safe_str(T("#-1 ALLOCATION ERROR"), buff, bp); + return false; + } + BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); + + bmem = BIO_new_mem_buf(encoded, len); + if (!bmem) { + safe_str(T("#-1 ALLOCATION ERROR"), buff, bp); + BIO_free(b64); + return false; + } + len = BIO_set_close(bmem, BIO_NOCLOSE); + + bio = BIO_push(b64, bmem); + + sbp = *bp; + while (true) { + char decoded[BUFFER_LEN]; + int dlen; + + dlen = BIO_read(bio, decoded, BUFFER_LEN); + if (dlen > 0) { + int n; + for (n = 0; n < dlen; n++) { + if (decoded[n] == TAG_START) { + int end; + n += 1; + for (end = n; end < dlen; end++) { + if (decoded[end] == TAG_END) + break; + } + if (end == dlen || decoded[n] != MARKUP_COLOR) { + BIO_free_all(bio); + *bp = sbp; + safe_str(T("#-1 CONVERSION ERROR"), buff, bp); + return false; + } + for (; n < end; n++) { + if (!valid_ansi_codes[(unsigned char) decoded[n]]) { + BIO_free_all(bio); + *bp = sbp; + safe_str(T("#-1 CONVERSION ERROR"), buff, bp); + return false; + } + } + n = end; + } else if (!isprint((unsigned char) decoded[n])) + decoded[n] = '?'; + } + safe_strl(decoded, dlen, buff, bp); + } else if (dlen == 0) + break; + else { + *bp = sbp; + safe_str(T("#-1 CONVERSION ERROR"), buff, bp); + return false; + } + } + + BIO_free_all(bio); + + return true; +#else +decode_base64(char *encoded __attribute__ ((__unused__)), int len __attribute__ ((__unused__)), char *buff, char **bp) +{ + safe_str(T("#-1 FUNCTION DISABLED"), buff, bp); + return false; #endif +} +/* Encode a string in base64 */ +FUNCTION(fun_encode64) +{ + encode_base64(args[0], arglens[0], buff, bp); +} + +/* Decode a string from base64 */ +FUNCTION(fun_decode64) +{ + decode_base64(args[0], arglens[0], buff, bp); +} + /* Copy over only alphanumeric chars */ static char * crunch_code(char *code) @@ -81,7 +225,7 @@ crypt_code(char *code, char *text, int type) return (char *) ""; if (!code || !*code) return text; - strcpy(codebuff, crunch_code(code)); + mush_strncpy(codebuff, crunch_code(code), BUFFER_LEN); if (!*codebuff) return text; textbuff[0] = '\0'; @@ -110,12 +254,60 @@ crypt_code(char *code, char *text, int type) FUNCTION(fun_encrypt) { - safe_str(crypt_code(args[1], args[0], 1), buff, bp); + char tbuff[BUFFER_LEN], *tp; + char *pass; + size_t len; + ansi_string *as = parse_ansi_string(args[0]); + + pass = remove_markup(args[1], &len); + + tp = tbuff; + safe_str(crypt_code(pass, as->text, 1), tbuff, &tp); + *tp = '\0'; + memcpy(as->text, tbuff, as->len); + + if (nargs == 3 && parse_boolean(args[2])) { + tp = tbuff; + safe_ansi_string(as, 0, as->len, tbuff, &tp); + if (!encode_base64(tbuff, tp - tbuff, buff, bp)) { + free_ansi_string(as); + return; + } + } else + safe_ansi_string(as, 0, as->len, buff, bp); + + free_ansi_string(as); } FUNCTION(fun_decrypt) { - safe_str(crypt_code(args[1], args[0], 0), buff, bp); + char tbuff[BUFFER_LEN], *tp; + char *pass; + size_t len; + ansi_string *as; + char *input; + + if (nargs == 3 && parse_boolean(args[2])) { + tp = tbuff; + if (!decode_base64(args[0], arglens[0], tbuff, &tp)) { + safe_strl(tbuff, tp - tbuff, buff, bp); + return; + } + *tp = '\0'; + input = tbuff; + } else + input = args[0]; + + as = parse_ansi_string(input); + + pass = remove_markup(args[1], &len); + + tp = tbuff; + safe_str(crypt_code(pass, as->text, 0), tbuff, &tp); + *tp = '\0'; + memcpy(as->text, tbuff, as->len + 1); + safe_ansi_string(as, 0, as->len, buff, bp); + free_ansi_string(as); } FUNCTION(fun_checkpass) @@ -187,7 +379,6 @@ FUNCTION(fun_digest) #endif } -#ifdef HAS_OPENSSL static void safe_hexchar(unsigned char c, char *buff, char **bp) { @@ -201,4 +392,3 @@ safe_hexchar(unsigned char c, char *buff, char **bp) (*bp)++; } } -#endif diff --git a/src/function.c b/src/function.c index 1ad90c1..1c20ba8 100644 --- a/src/function.c +++ b/src/function.c @@ -25,24 +25,70 @@ #include "flags.h" #include "game.h" #include "mymalloc.h" +#include "sort.h" #include "funs.h" #include "confmagic.h" +#include "ansi.h" static void func_hash_insert(const char *name, FUN *func); static int apply_restrictions(unsigned int result, const char *restriction); - +static char *build_function_report(dbref player, FUN *fp); + USERFN_ENTRY *userfn_tab; /**< Table of user-defined functions */ HASHTAB htab_function; /**< Function hash table */ HASHTAB htab_user_function; /**< User-defined function hash table */ - +slab *function_slab; /**< slab for 'struct fun' allocations */ +slab *userfun_slab; /**< slab for 'struct userfn_entry' allocations */ + /* -------------------------------------------------------------------------* * Utilities. */ +/* Save and restore regexp data */ +void +save_regexp_context(struct re_save *save) +{ + save->re_code = global_eval_context.re_code; + save->re_from = global_eval_context.re_from; + save->re_subpatterns = global_eval_context.re_subpatterns; + save->re_offsets = global_eval_context.re_offsets; +} + +void +restore_regexp_context(struct re_save *save) +{ + global_eval_context.re_code = save->re_code; + global_eval_context.re_from = save->re_from; + global_eval_context.re_subpatterns = save->re_subpatterns; + global_eval_context.re_offsets = save->re_offsets; +} + +/** Save a single q-register + */ +void +save_partial_global_reg(const char *funcname, char *preserve[], int i) +{ + preserve[i] = mush_strdup(global_eval_context.renv[i], funcname); +} + +/** Restore q-registers saved with save_partial_global_reg() + */ +void +restore_partial_global_regs(const char *funcname, char *preserve[]) +{ + int i; + for (i = 0; i < NUMQ; i++) { + if (preserve[i]) { + mush_strncpy(global_eval_context.renv[i], preserve[i], BUFFER_LEN); + mush_free(preserve[i], funcname); + } + } +} /** Save a copy of the q-registers. * \param funcname name of function calling (for memory leak testing) * \param preserve pointer to array to store the q-registers in. */ + void save_global_regs(const char *funcname, char *preserve[]) { @@ -52,8 +98,7 @@ save_global_regs(const char *funcname, char *preserve[]) if (!global_eval_context.renv[i][0]) preserve[i] = NULL; else { - preserve[i] = (char *) mush_malloc(BUFFER_LEN, funcname); - strcpy(preserve[i], global_eval_context.renv[i]); + preserve[i] = mush_strdup(global_eval_context.renv[i], funcname); } } } @@ -68,7 +113,7 @@ restore_global_regs(const char *funcname, char *preserve[]) int i; for (i = 0; i < NUMQ; i++) { if (preserve[i]) { - strcpy(global_eval_context.renv[i], preserve[i]); + mush_strncpy(global_eval_context.renv[i], preserve[i], BUFFER_LEN); mush_free(preserve[i], funcname); preserve[i] = NULL; } else { @@ -165,8 +210,7 @@ save_global_nxt(const char *funcname, char *preservew[], char *preserver[], if (!global_eval_context.rnxt[i]) valr[i] = NULL; else { - valr[i] = (char *) mush_malloc(BUFFER_LEN, funcname); - strcpy(valr[i], global_eval_context.rnxt[i]); + valr[i] = mush_strdup(global_eval_context.rnxt[i], funcname); } } for (i = 0; i < 10; i++) { @@ -174,8 +218,7 @@ save_global_nxt(const char *funcname, char *preservew[], char *preserver[], if (!global_eval_context.wnxt[i]) valw[i] = NULL; else { - valw[i] = (char *) mush_malloc(BUFFER_LEN, funcname); - strcpy(valw[i], global_eval_context.wnxt[i]); + valw[i] = mush_strdup(global_eval_context.wnxt[i], funcname); } } } @@ -196,7 +239,7 @@ restore_global_nxt(const char *funcname, char *preservew[], char *preserver[], global_eval_context.rnxt[i] = preserver[i]; if (preserver[i]) { /* There was a former address, so we can restore to it */ - strcpy(global_eval_context.rnxt[i], valr[i]); + mush_strncpy(global_eval_context.rnxt[i], valr[i], BUFFER_LEN); mush_free(valr[i], funcname); valr[i] = NULL; } @@ -205,13 +248,14 @@ restore_global_nxt(const char *funcname, char *preservew[], char *preserver[], global_eval_context.wnxt[i] = preservew[i]; if (preservew[i]) { /* There was a former address, so we can restore to it */ - strcpy(global_eval_context.wnxt[i], valw[i]); + mush_strncpy(global_eval_context.wnxt[i], valw[i], BUFFER_LEN); mush_free(valw[i], funcname); valw[i] = NULL; } } } + /** Check for a delimiter in an argument of a function call. * This function checks a given argument of a function call and sees * if it could be used as a delimiter. A delimiter must be a single @@ -281,8 +325,10 @@ FUNTAB flist[] = { {"ANDFLAGS", fun_andflags, 2, 2, FN_REG}, {"ANDLFLAGS", fun_andlflags, 2, 2, FN_REG}, {"ANDLPOWERS", fun_andlflags, 2, 2, FN_REG}, - {"ANDPOWERS", fun_andflags, 2, 2, FN_REG}, - {"ANSI", fun_ansi, 2, -2, FN_NOPARSE}, + {"ANSI", fun_ansi, 2, -2, FN_REG}, +#ifdef ANSI_DEBUG + {"ANSIINSPECT", fun_ansiinspect, 1, 2, FN_REG}, +#endif {"APOSS", fun_aposs, 1, 1, FN_REG}, {"APPLY", fun_apply, 1, 3, FN_REG}, {"ARABIC2ROMAN", fun_arabictoroman, 1, 1, FN_REG}, @@ -308,6 +354,7 @@ FUNTAB flist[] = { {"CAT", fun_cat, 1, INT_MAX, FN_REG}, #ifdef CHAT_SYSTEM {"CBUFFER", fun_cinfo, 1, 1, FN_REG}, + {"CBUFFERADD", fun_cbufferadd, 2, 3, FN_REG}, {"CDESC", fun_cinfo, 1, 1, FN_REG}, {"CEMIT", fun_cemit, 2, 3, FN_REG}, {"CFLAGS", fun_cflags, 1, 2, FN_REG}, @@ -333,6 +380,8 @@ FUNTAB flist[] = { #endif /* CHAT_SYSTEM */ {"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}, @@ -341,10 +390,12 @@ FUNTAB flist[] = { {"CONVTIME", fun_convtime, 1, 1, FN_REG}, {"COR", fun_cor, 2, INT_MAX, FN_NOPARSE}, {"CREATE", fun_create, 1, 2, FN_REG}, - {"CTIME", fun_ctime, 1, 1, FN_REG}, + {"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}, @@ -361,7 +412,8 @@ FUNTAB flist[] = { {"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}, {"EMPOWER", fun_empower, 2, 2, FN_REG}, {"ENTRANCES", fun_entrances, 0, 4, FN_REG}, {"ETIMEFMT", fun_etimefmt, 2, 2, FN_REG}, @@ -378,6 +430,7 @@ FUNTAB flist[] = { {"FLAGS", fun_flags, 0, 1, FN_REG}, {"FLIP", fun_flip, 1, -1, FN_REG}, {"FLOORDIV", fun_floordiv, 2, 2, FN_REG}, + {"FN", fun_fn, 1, INT_MAX, FN_NOPARSE}, {"FOLD", fun_fold, 2, 4, FN_REG}, #ifdef USE_MAILER {"FOLDERSTATS", fun_folderstats, 0, 2, FN_REG}, @@ -386,7 +439,7 @@ FUNTAB flist[] = { {"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}, @@ -397,10 +450,10 @@ FUNTAB flist[] = { {"GREPI", fun_grep, 3, 3, FN_REG}, {"GT", fun_gt, 2, 2, FN_REG}, {"GTE", fun_gte, 2, 2, FN_REG}, - {"HASATTR", fun_hasattr, 2, 2, FN_REG}, - {"HASATTRP", fun_hasattr, 2, 2, FN_REG}, - {"HASATTRPVAL", fun_hasattr, 2, 2, FN_REG}, - {"HASATTRVAL", fun_hasattr, 2, 2, FN_REG}, + {"HASATTR", fun_hasattr, 1, 2, FN_REG}, + {"HASATTRP", fun_hasattr, 1, 2, FN_REG}, + {"HASATTRPVAL", fun_hasattr, 1, 2, FN_REG}, + {"HASATTRVAL", fun_hasattr, 1, 2, FN_REG}, {"HASFLAG", fun_hasflag, 2, 2, FN_REG}, {"HASPOWER", fun_hasdivpower, 2, 2, FN_REG}, {"HASPOWERGROUP", fun_haspowergroup, 2, 2, FN_REG}, @@ -427,19 +480,22 @@ FUNTAB flist[] = { {"ISDBREF", fun_isdbref, 1, 1, FN_REG}, {"ISINT", fun_isint, 1, 1, FN_REG}, {"ISNUM", fun_isnum, 1, 1, FN_REG}, + {"ISOBJID", fun_isobjid, 1, 1, FN_REG}, {"ISWORD", fun_isword, 1, 1, FN_REG}, {"ITER", fun_iter, 2, 4, FN_NOPARSE}, {"ITEMS", fun_items, 2, 2, FN_REG}, {"ITEMIZE", fun_itemize, 1, 4, FN_REG}, {"ITEXT", fun_itext, 1, 1, FN_REG}, {"LAST", fun_last, 1, 2, FN_REG}, - {"LATTR", fun_lattr, 1, 1, FN_REG}, + {"LATTR", fun_lattr, 1, 2, FN_REG}, + {"LATTRP", fun_lattr, 1, 2, FN_REG}, {"LCON", fun_dbwalker, 1, 1, FN_REG}, {"LCSTR", fun_lcstr, 1, -1, FN_REG}, {"LDELETE", fun_ldelete, 2, 3, FN_REG}, {"LDIVISIONS", fun_dbwalker, 1, 1, FN_REG}, {"LEFT", fun_left, 2, 2, FN_REG}, {"LEMIT", fun_lemit, 1, -1, FN_REG}, + {"LETQ", fun_letq, 1, INT_MAX, FN_NOPARSE}, {"LEXITS", fun_dbwalker, 1, 1, FN_REG}, {"LFLAGS", fun_lflags, 0, 1, FN_REG}, {"LINK", fun_link, 2, 3, FN_REG}, @@ -455,7 +511,7 @@ FUNTAB flist[] = { {"LOCK", fun_lock, 1, 2, FN_REG}, {"LPARENT", fun_lparent, 1, 1, FN_REG}, {"LPLAYERS", fun_dbwalker, 1, 1, FN_REG}, - {"LPORTS", fun_lports, 0, 0, FN_REG}, + {"LPORTS", fun_lports, 0, 1, FN_REG}, {"LPOS", fun_lpos, 2, 2, FN_REG}, {"LTHINGS", fun_dbwalker, 1, 1, FN_REG}, {"LSEARCH", fun_lsearch, 1, INT_MAX, FN_REG}, @@ -488,12 +544,14 @@ FUNTAB flist[] = { {"MEDIAN", fun_median, 1, INT_MAX, FN_REG}, {"MEMBER", fun_member, 2, 3, FN_REG}, {"MERGE", fun_merge, 3, 3, FN_REG}, + {"MESSAGE", fun_message, 3, 13, FN_REG}, {"MID", fun_mid, 3, 3, FN_REG}, {"MIN", fun_min, 1, INT_MAX, FN_REG}, {"MIX", fun_mix, 3, 12, FN_REG}, {"MODULO", fun_modulo, 2, 2, FN_REG}, {"MONEY", fun_money, 1, 1, FN_REG}, - {"MTIME", fun_mtime, 1, 1, FN_REG}, + {"MSECS", fun_msecs, 1, 1, FN_REG}, + {"MTIME", fun_mtime, 1, 2, FN_REG}, {"MUDNAME", fun_mudname, 0, 0, FN_REG}, {"MUL", fun_mul, 2, INT_MAX, FN_REG}, {"MUNGE", fun_munge, 3, 5, FN_REG}, @@ -507,6 +565,8 @@ FUNTAB flist[] = { {"NATTR", 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}, {"NTHINGS", fun_dbwalker, 1, 1, FN_REG}, @@ -546,7 +606,6 @@ FUNTAB flist[] = { {"ORFLAGS", fun_orflags, 2, 2, FN_REG}, {"ORLFLAGS", fun_orlflags, 2, 2, FN_REG}, {"ORLPOWERS", fun_orlflags, 2, 2, FN_REG}, - {"ORPOWERS", fun_orflags, 2, 2, FN_REG}, {"OOREF", fun_ooref, 0, 0, FN_REG}, {"OWNER", fun_owner, 1, 1, FN_REG}, {"PARENT", fun_parent, 1, 2, FN_REG}, @@ -555,6 +614,7 @@ FUNTAB flist[] = { {"PGHASPOWER", fun_pghaspower, 3, 4, FN_REG}, {"PGPOWERS", fun_pgpowers, 2, 2, FN_REG}, {"PLAYERMEM", fun_playermem, 1, 1, FN_REG}, + {"PLAYER", fun_player, 1, 1, FN_REG}, {"PMATCH", fun_pmatch, 1, 1, FN_REG}, {"POLL", fun_poll, 0, 0, FN_REG}, {"PORTS", fun_ports, 1, 1, FN_REG}, @@ -629,6 +689,7 @@ FUNTAB flist[] = { {"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}, #ifdef _SWMP_ @@ -646,7 +707,7 @@ FUNTAB flist[] = { {"STRIPACCENTS", fun_stripaccents, 1, 1, FN_REG}, {"STRIPANSI", fun_stripansi, 1, -1, FN_REG}, {"STRLEN", fun_strlen, 1, -1, FN_REG}, - {"STRMATCH", fun_strmatch, 2, 2, FN_REG}, + {"STRMATCH", fun_strmatch, 2, 3, FN_REG}, {"STRREPLACE", fun_strreplace, 4, 4, FN_REG}, {"SUB", fun_sub, 2, 2, FN_REG}, {"SUBJ", fun_subj, 1, 1, FN_REG}, @@ -694,6 +755,8 @@ FUNTAB flist[] = { {"XGET", fun_xget, 2, 2, FN_REG}, {"XOR", fun_xor, 2, INT_MAX, FN_REG}, {"XCON", fun_dbwalker, 3, 3, FN_REG}, + {"XATTR", fun_lattr, 3, 4, FN_REG}, + {"XATTRP", fun_lattr, 3, 4, FN_REG}, {"XEXITS", fun_dbwalker, 3, 3, FN_REG}, {"XPLAYERS", fun_dbwalker, 3, 3, FN_REG}, {"XTHINGS", fun_dbwalker, 3, 3, FN_REG}, @@ -771,8 +834,8 @@ void do_list_functions(dbref player, int lc) { /* lists all built-in functions. */ - char *b = list_functions(); - notify_format(player, "Functions: %s", lc ? strlower(b) : b); + char *b = list_functions(NULL); + notify_format(player, T("Functions: %s"), lc ? strlower(b) : b); } /** Return a list of function names. @@ -780,33 +843,55 @@ do_list_functions(dbref player, int lc) * \return list of function names as a static string. */ char * -list_functions(void) +list_functions(const char *type) { FUN *fp; const char *ptrs[BUFFER_LEN / 2]; static char buff[BUFFER_LEN]; char *bp; int nptrs = 0, i; - for (fp = (FUN *) hash_firstentry(&htab_function); - fp; fp = (FUN *) hash_nextentry(&htab_function)) { - if (fp->flags & FN_OVERRIDE) - continue; - ptrs[nptrs++] = fp->name; + int which = 0; + /* 0x1 for builtin, 0x2 for @function */ + + if (!type) + which = 0x3; + else if (strcmp(type, "all") == 0) + which = 0x3; + else if (strcmp(type, "builtin") == 0) + which = 0x1; + else if (strcmp(type, "local") == 0) + which = 0x2; + else { + mush_strncpy(buff, T("#-1 INVALID ARGUMENT"), BUFFER_LEN); + return buff; } - fp = (FUN *) hash_firstentry(&htab_user_function); - while (fp) { - ptrs[nptrs++] = fp->name; - fp = (FUN *) hash_nextentry(&htab_user_function); + + if (which & 0x1) { + for (fp = hash_firstentry(&htab_function); + fp; fp = hash_nextentry(&htab_function)) { + if (fp->flags & FN_OVERRIDE) + continue; + ptrs[nptrs++] = fp->name; + } + } + + if (which & 0x2) { + for (fp = hash_firstentry(&htab_user_function); + fp; fp = hash_nextentry(&htab_user_function)) + ptrs[nptrs++] = fp->name; } + /* do_gensort needs a dbref now, but only for sort types that aren't * used here anyway */ - do_gensort((dbref) 0, (char **) ptrs, NULL, nptrs, 0); + do_gensort(0, (char **) ptrs, NULL, nptrs, 0); bp = buff; - safe_str(ptrs[0], buff, &bp); - for (i = 1; i < nptrs; i++) { - safe_chr(' ', buff, &bp); - safe_str(ptrs[i], buff, &bp); - } + if (nptrs > 0) { + safe_str(ptrs[0], buff, &bp); + for (i = 1; i < nptrs; i++) { + safe_chr(' ', buff, &bp); + safe_str(ptrs[i], buff, &bp); + } + } *bp = '\0'; return buff; } @@ -830,6 +915,18 @@ func_hash_lookup(const char *name) return f; } +/** Look up a function by name, builtins only. + * \param name name of function to look up. + * \return pointer to function data, or NULL. + */ +FUN * +builtin_func_hash_lookup(const char *name) +{ + FUN *f; + f = (FUN *) hashfind(strupper(name), &htab_function); + return f; +} + static void func_hash_insert(const char *name, FUN *func) { @@ -845,8 +942,9 @@ init_func_hashtab(void) { FUNTAB *ftp; - hashinit(&htab_function, 512, sizeof(FUN)); - hash_init(&htab_user_function, 32, sizeof(FUN), delete_function); + hashinit(&htab_function, 512); + hash_init(&htab_user_function, 32, delete_function); + function_slab = slab_create("functions", sizeof(FUN)); for (ftp = flist; ftp->name; ftp++) { function_add(ftp->name, ftp->fun, ftp->minargs, ftp->maxargs, ftp->flags); } @@ -861,9 +959,7 @@ init_func_hashtab(void) void function_init_postconfig(void) { - userfn_tab = - (USERFN_ENTRY *) mush_malloc(MAX_GLOBAL_FNS * sizeof(USERFN_ENTRY), - "userfn_tab"); + userfn_tab = mush_calloc(MAX_GLOBAL_FNS, sizeof(USERFN_ENTRY), "userfn_tab"); } /** Check permissions to run a function. @@ -940,7 +1036,10 @@ function_add(const char *name, function_func fun, int minargs, int maxargs, int ftype) { FUN *fp; - fp = (FUN *) mush_malloc(sizeof(FUN), "function"); + + if (!name || name[0] == '\0') + return; + fp = slab_malloc(function_slab, NULL); memset(fp, 0, sizeof(FUN)); fp->name = name; fp->where.fun = fun; @@ -991,13 +1090,20 @@ strip_braces(const char *str) */ -static Size_t userfn_count = 0; +static size_t userfn_count = 0; static int -apply_restrictions(unsigned int result, const char *restriction) +apply_restrictions(unsigned int result, const char *xres) { int flag, clear = 0; char *tp; + char *restriction, *rsave; + + if (!xres || !*xres) + return 0; + + rsave = restriction = mush_strdup(xres, "ar.string"); + while (restriction && *restriction) { if ((tp = strchr(restriction, ' '))) *tp++ = '\0'; @@ -1036,6 +1142,8 @@ apply_restrictions(unsigned int result, const char *restriction) flag = FN_LOCALIZE; } else if (!strcasecmp(restriction, "ulocal")) { flag = FN_LOCALIZE; + } else if (!strcasecmp(restriction, "userfn")) { + flag = FN_USERFN; } if (clear) result &= ~flag; @@ -1043,6 +1151,7 @@ apply_restrictions(unsigned int result, const char *restriction) result |= flag; restriction = tp; } + mush_free(rsave, "ar.string"); return result; } @@ -1062,6 +1171,7 @@ apply_restrictions(unsigned int result, const char *restriction) * noplayer can't be used by players, just objects/rooms/exits * nosidefx can't be used to do side-effect thingies * localize localize q-registers + * userfn can only be used inside @functions. * \endverbatim * \param name name of function to restrict. * \param restriction name of restriction to apply to function. @@ -1089,12 +1199,16 @@ restrict_function(const char *name, const char *restriction) * \param player the enactor. * \param name name of function to restrict. * \param restriction name of restriction to add. + * \param builtin operate on the builtin version, whether overridden or not */ void -do_function_restrict(dbref player, const char *name, const char *restriction) +do_function_restrict(dbref player, const char *name, const char *restriction, + int builtin) { FUN *fp; unsigned int flags; + char tbuf1[BUFFER_LEN]; + char *bp = tbuf1; if (!Global_Funcs(player)) { notify(player, T("Permission denied.")); @@ -1108,20 +1222,49 @@ do_function_restrict(dbref player, const char *name, const char *restriction) notify(player, T("Do what with the function?")); return; } - fp = func_hash_lookup(name); + fp = builtin ? builtin_func_hash_lookup(name) : func_hash_lookup(name); if (!fp) { notify(player, T("No such function.")); return; } flags = fp->flags; fp->flags = apply_restrictions(flags, restriction); + if (fp->flags & FN_BUILTIN) + safe_format(tbuf1, &bp, "%s %s - ", T("Builtin function"), fp->name); + else + safe_format(tbuf1, &bp, "%s #%d/%s - ", T("@function"), + userfn_tab[fp->where.offset].thing, + userfn_tab[fp->where.offset].name); if (fp->flags == flags) - notify(player, T("Restrictions unchanged.")); + safe_str(T("Restrictions unchanged."), tbuf1, &bp); else - notify(player, T("Restrictions modified.")); + safe_str(T("Restrictions modified."), tbuf1, &bp); + *bp = '\0'; + notify(player, tbuf1); } +/* Sort FUN*s by dbref and then function name */ +static int +func_comp(const void *s1, const void *s2) +{ + const FUN *a, *b; + dbref da, db; + + a = *(const FUN **) s1; + b = *(const FUN **) s2; + + da = userfn_tab[a->where.offset].thing; + db = userfn_tab[b->where.offset].thing; + + if (da == db) + return strcmp(a->name, b->name); + else if (da < db) + return -1; + else + return 1; +} + /** Add a user-defined function. * \verbatim * This is the implementation of the @function command. If no arguments @@ -1156,22 +1299,42 @@ do_function(dbref player, char *name, char *argv[], int preserve) /* if the player is privileged, display user-def'ed functions * with corresponding dbref number of thing and attribute name. */ + FUN **funclist; + int n = 0; + + funclist = mush_calloc(userfn_count, sizeof(FUN *), "function.fp.list"); notify(player, T("Function Name Dbref # Attrib")); for (fp = (FUN *) hash_firstentry(&htab_user_function); fp; fp = (FUN *) hash_nextentry(&htab_user_function)) { + funclist[n] = fp; + n++; + } + qsort(funclist, userfn_count, sizeof(FUN *), func_comp); + for (n = 0; n < (int) userfn_count; n++) { + fp = funclist[n]; notify_format(player, "%-32s %6d %s", fp->name, userfn_tab[fp->where.offset].thing, userfn_tab[fp->where.offset].name); } + mush_free(funclist, "function.fp.list"); } else { + const char **funcnames; + int n = 0; /* just print out the list of available functions */ safe_str(T("User functions:"), tbuf1, &bp); + funcnames = mush_calloc(userfn_count, sizeof(char *), "function.list"); for (fp = (FUN *) hash_firstentry(&htab_user_function); fp; fp = (FUN *) hash_nextentry(&htab_user_function)) { + funcnames[n] = fp->name; + n++; + } + qsort(funcnames, userfn_count, sizeof(char *), str_comp); + for (n = 0; n < (int) userfn_count; n++) { safe_chr(' ', tbuf1, &bp); - safe_str(fp->name, tbuf1, &bp); + safe_str(funcnames[n], tbuf1, &bp); } + mush_free(funcnames, "function.list"); *bp = '\0'; notify(player, tbuf1); } @@ -1216,7 +1379,7 @@ do_function(dbref player, char *name, char *argv[], int preserve) fp = func_hash_lookup(upcasestr(name)); if (!fp) { - if (userfn_count >= (Size_t) MAX_GLOBAL_FNS) { + if (userfn_count >= (size_t) MAX_GLOBAL_FNS) { notify(player, T("Function table full.")); return; } @@ -1225,7 +1388,7 @@ do_function(dbref player, char *name, char *argv[], int preserve) return; } /* a completely new entry. First, insert it into general hash table */ - fp = (FUN *) mush_malloc(sizeof(FUN), "func_hash.FUN"); + fp = slab_malloc(function_slab, NULL); fp->name = mush_strdup(name, "func_hash.name"); fp->where.offset = userfn_count; if (argv[3] && *argv[3]) { @@ -1270,11 +1433,11 @@ do_function(dbref player, char *name, char *argv[], int preserve) return; } if (fp->flags & FN_BUILTIN) { /* Overriding a built in function */ - if (userfn_count >= (Size_t) MAX_GLOBAL_FNS) { + if (userfn_count >= (size_t) MAX_GLOBAL_FNS) { notify(player, T("Function table full.")); return; } - fp = (FUN *) mush_malloc(sizeof(FUN), "func_hash.FUN"); + fp = slab_malloc(function_slab, NULL); fp->name = mush_strdup(name, "func_hash.name"); fp->where.offset = userfn_count; fp->flags = 0; @@ -1326,12 +1489,12 @@ delete_function(void *data) table_index = fp->where.offset; mush_free((void *) fp->name, "func_hash.name"); - mush_free(fp, "func_hash.FUN"); + slab_free(function_slab, fp); /* Fix up the user function table. Expensive, but how often will * we need to delete an @function anyway? */ - mush_free((Malloc_t) userfn_tab[table_index].name, "userfn_tab.name"); - mush_free((Malloc_t) userfn_tab[table_index].fn, "usrfn_tab.fn"); + mush_free(userfn_tab[table_index].name, "userfn_tab.name"); + mush_free(userfn_tab[table_index].fn, "usrfn_tab.fn"); userfn_count--; for (i = table_index; i < userfn_count; i++) { fp = (FUN *) hashfind(userfn_tab[i + 1].fn, &htab_user_function); @@ -1476,32 +1639,46 @@ do_function_toggle(dbref player, char *name, int toggle) void do_function_report(dbref player, char *name) { - FUN *fp; - char tbuf[BUFFER_LEN]; - char *tp; - const char *state, *state2; - int first = 1; - int maxargs; + FUN *fp, *bfp; fp = func_hash_lookup(name); if (!fp) { notify(player, T("No such function.")); return; } + notify(player, build_function_report(player, fp)); + + bfp = builtin_func_hash_lookup(name); + if (bfp && (fp != bfp)) + notify(player, build_function_report(player, bfp)); +} + +static char * +build_function_report(dbref player, FUN *fp) +{ + char tbuf[BUFFER_LEN]; + char *tp = tbuf; + static char buff[BUFFER_LEN]; + char *bp = buff; + const char *state, *state2; + int first = 1; + int maxargs; if (fp->flags & FN_BUILTIN) - state2 = ""; + state2 = " builtin"; else state2 = " @function"; if (fp->flags & FN_DISABLED) state = "Disabled"; + else if (fp->flags & FN_OVERRIDE) + state = "Overridden"; else state = "Enabled"; - notify_format(player, T("Name : %s() (%s%s)"), fp->name, state, state2); + safe_format(buff, &bp, T("Name : %s() (%s%s)"), fp->name, state, state2); + safe_chr('\n', buff, &bp); - tp = tbuf; tbuf[0] = '\0'; if (fp->flags & FN_NOPARSE) { safe_str("Noparse", tbuf, &tp); @@ -1516,6 +1693,13 @@ do_function_report(dbref player, char *name) first = 0; } + if (fp->flags & FN_LOCALIZE) { + if (first == 0) + safe_strl(", ", 2, tbuf, &tp); + safe_str("Userfn", tbuf, &tp); + first = 0; + } + if (fp->flags & FN_LITERAL) { if (first == 0) safe_strl(", ", 2, tbuf, &tp); @@ -1593,12 +1777,14 @@ do_function_report(dbref player, char *name) } *tp = '\0'; - notify_format(player, T("Flags : %s"), tbuf); + safe_format(buff, &bp, T("Flags : %s"), tbuf); + safe_chr('\n', buff, &bp); if (!(fp->flags & FN_BUILTIN) && Global_Funcs(player)) { - notify_format(player, T("Location : #%d/%s"), - userfn_tab[fp->where.offset].thing, - userfn_tab[fp->where.offset].name); + safe_format(buff, &bp, T("Location : #%d/%s"), + userfn_tab[fp->where.offset].thing, + userfn_tab[fp->where.offset].name); + safe_chr('\n', buff, &bp); } maxargs = abs(fp->maxargs); @@ -1612,10 +1798,12 @@ do_function_report(dbref player, char *name) tbuf[0] = '\0'; if (fp->minargs == maxargs) - notify_format(player, T("Arguments : %d %s"), fp->minargs, tbuf); + safe_format(buff, &bp, T("Arguments : %d %s"), fp->minargs, tbuf); else if (fp->maxargs == INT_MAX) - notify_format(player, T("Arguments : At least %d %s"), fp->minargs, tbuf); + safe_format(buff, &bp, T("Arguments : At least %d %s"), fp->minargs, tbuf); else - notify_format(player, - T("Arguments : %d to %d %s"), fp->minargs, maxargs, tbuf); + safe_format(buff, &bp, + T("Arguments : %d to %d %s"), fp->minargs, maxargs, tbuf); + *bp = '\0'; + return buff; } diff --git a/src/fundb.c b/src/fundb.c index e95c282..77784c0 100644 --- a/src/fundb.c +++ b/src/fundb.c @@ -39,10 +39,9 @@ static int lattr_helper(dbref player, dbref thing, dbref parent, char const *pat ATTR *atr, void *args); static dbref - dbwalk(char *buff, char **bp, dbref executor, dbref enactor, - int type, dbref loc, dbref after, int skipdark, - int start, int count, int *retcount); - +dbwalk(char *buff, char **bp, dbref executor, dbref enactor, + int type, dbref loc, dbref after, int skipdark, + int start, int count, int *retcount); const char * do_get_attrib(dbref executor, dbref thing, const char *attrib) @@ -76,6 +75,7 @@ struct lh_args { int first; /**< Is this is the first attribute, or later? */ char *buff; /**< Buffer to store output */ char **bp; /**< Pointer to address of insertion point in buff */ + char delim; /**< Delimiter */ }; /* this function produces a space-separated list of attributes that are @@ -93,7 +93,7 @@ lattr_helper(dbref player __attribute__ ((__unused__)), if (lh->first) lh->first = 0; else - safe_chr(' ', lh->buff, lh->bp); + safe_chr(lh->delim, lh->buff, lh->bp); safe_str(AL_NAME(atr), lh->buff, lh->bp); return 1; } @@ -108,6 +108,7 @@ FUNCTION(fun_lattr) dbref thing; char *pattern; struct lh_args lh; + char delim; pattern = strchr(args[0], '/'); if (pattern) @@ -127,6 +128,7 @@ FUNCTION(fun_lattr) lh.first = 1; lh.buff = buff; lh.bp = bp; + lh.delim = delim; (void) atr_iter_get(executor, thing, pattern, 0, lattr_helper, &lh); } @@ -150,17 +152,29 @@ FUNCTION(fun_nattr) FUNCTION(fun_hasattr) { dbref thing; + char *attr; ATTR *a; + if (nargs == 1) { + attr = strchr(args[0], '/'); + if (!attr) { + safe_format(buff, bp, T("#-1 BAD ARGUMENT FORMAT TO %s"), called_as); + return; + } + *attr++ = '\0'; + } else { + attr = args[1]; + } + thing = match_thing(executor, args[0]); if (!GoodObject(thing)) { safe_str(T(e_notvis), buff, bp); return; } if (strchr(called_as, 'P')) - a = atr_get(thing, upcasestr(args[1])); + a = atr_get(thing, upcasestr(attr)); else - a = atr_get_noparent(thing, upcasestr(args[1])); + a = atr_get_noparent(thing, upcasestr(attr)); if (a && Can_Read_Attr(executor, thing, a)) { if (strchr(called_as, 'V')) safe_chr(*AL_STR(a) ? '1' : '0', buff, bp); @@ -753,6 +767,7 @@ FUNCTION(fun_entrances) int found; int exd, td, pd, rd; /* what we're looking for */ char *p; + int controlswhere = 0; if (!command_check_byname(executor, "@entrances")) { safe_str(T(e_perm), buff, bp); @@ -829,20 +844,15 @@ FUNCTION(fun_entrances) if (!GoodObject(high)) high = db_top - 1; - if (!controls(executor, where) && !CanSearch(executor, where)) { + controlswhere = controls(executor, where); + if (!controlswhere && !CanSearch(executor, where)) { safe_str(T(e_perm), buff, bp); return; } - if (!payfor(executor, FIND_COST)) { - notify_format(executor, T("You don't have %d %s to do that."), - FIND_COST, ((FIND_COST == 1) ? MONEY : MONIES)); - safe_str("#-1", buff, bp); - return; - } /* Ok, do the real work */ found = 0; for (counter = low; counter <= high; counter++) { - if (controls(executor, where) || controls(executor, counter)) { + if (GoodObject(counter) && (controls(executor, where) || controls(executor, counter))) { if ((exd && IsExit(counter)) || (td && IsThing(counter)) || (pd && IsPlayer(counter)) || (rd && IsRoom(counter))) { @@ -851,11 +861,13 @@ FUNCTION(fun_entrances) else entrance = Location(counter); if (entrance == where) { - if (!found) - found = 1; - else - safe_chr(' ', buff, bp); - safe_dbref(counter, buff, bp); + if (controlswhere || controls(executor, counter)) { + if (!found) + found = 1; + else + safe_chr(' ', buff, bp); + safe_dbref(counter, buff, bp); + } } } } @@ -886,19 +898,34 @@ FUNCTION(fun_nearby) FUNCTION(fun_controls) { dbref it = match_thing(executor, args[0]); - dbref thing = match_thing(executor, args[1]); + dbref thing; + char *attrname; + + if (!GoodObject(it)) { + safe_str(T("#-1 ARG1 NOT FOUND"), buff, bp); + return; + } - if (!GoodObject(it)) - safe_str(T("#-1 ARG1 NOT FOUND"), buff, bp); - else if (!GoodObject(thing)) - safe_str(T("#-1 ARG2 NOT FOUND"), buff, bp); - else if (!(controls(executor, it) || controls(executor, thing) - || CanSee(executor, it) || CanSee(executor, thing))) - safe_str(T(e_perm), buff, bp); - else - safe_chr(controls(it, thing) ? '1' : '0', buff, bp); + if ((attrname = strchr(args[1], '/')) != NULL) + *attrname++ = '\0'; + thing = match_thing(executor, args[1]); + if (!GoodObject(thing)) { + safe_str(T("#-1 ARG2 NOT FOUND"), buff, bp); + return; + } + if (!(controls(executor, it) || controls(executor, thing) + || CanSee(executor, thing))) + safe_str(T(e_perm), buff, bp); + else if (attrname) { + if (!good_atr_name(upcasestr(attrname))) { + safe_str(T("#-1 BAD ATTR NAME"), buff, bp); + return; + } + safe_chr(can_edit_attr(it, thing, attrname) ? '1' : '0', buff, bp); + } else + safe_chr(controls(it, thing) ? '1' : '0', buff, bp); } - + /* ARGSUSED */ FUNCTION(fun_visible) { @@ -973,13 +1000,13 @@ FUNCTION(fun_hasflag) { dbref thing; ATTR *attrib; - int f; + privbits f = 0; if (strchr(args[0], '/')) { parse_attrib(executor, args[0], &thing, &attrib); if (!attrib) safe_str("#-1", buff, bp); - else if ((f = string_to_atrflag(executor, args[1])) < 0) + else if (string_to_atrflag(executor, args[1], &f) < 0) safe_str("#-1", buff, bp); else safe_boolean(AL_FLAGS(attrib) & f, buff, bp); @@ -1111,7 +1138,7 @@ FUNCTION(fun_lock) lock_type real_ltype; if ((ltype = strchr(args[0], '/'))) { - *ltype++ = '\0'; + *ltype ++ = '\0'; upcasestr(ltype); } @@ -1155,7 +1182,7 @@ FUNCTION(fun_elock) it = match_thing(executor, args[0]); ltype = get_locktype(p); - if (!GoodObject(it) || (ltype == NULL) || !Can_Read_Lock(executor, it, ltype)) { + if (!GoodObject(it) || (ltype == NULL) ||!Can_Read_Lock(executor, it, ltype)) { safe_str("#-1", buff, bp); return; } @@ -1224,24 +1251,59 @@ FUNCTION(fun_objid) /* ARGSUSED */ FUNCTION(fun_ctime) { + bool utc = 0; dbref it = match_thing(executor, args[0]); - if (GoodObject(it) && !IsGarbage(it)) - safe_str(show_time(CreTime(it), 0), buff, bp); + if (nargs == 2) + utc = parse_boolean(args[1]); + + if (!GoodObject(it) || IsGarbage(it)) + safe_str(T(e_notvis), buff, bp); + else if (!Can_Examine(executor, it)) + safe_str(T(e_perm), buff, bp); else + safe_str(show_time(CreTime(it), utc), buff, bp); +} + +FUNCTION(fun_csecs) +{ + dbref it = match_thing(executor, args[0]); + + if (!GoodObject(it) || IsGarbage(it)) safe_str(T(e_notvis), buff, bp); + else if (!Can_Examine(executor, it)) + safe_str(T(e_perm), buff, bp); + else + safe_integer((intmax_t) CreTime(it), buff, bp); } /* ARGSUSED */ FUNCTION(fun_mtime) { + bool utc = 0; dbref it = match_thing(executor, args[0]); + + if (nargs == 2) + utc = parse_boolean(args[1]); + if (!GoodObject(it) || IsGarbage(it)) safe_str(T(e_notvis), buff, bp); else if (!Can_Examine(executor, it) || IsPlayer(it)) safe_str(T(e_perm), buff, bp); else - safe_str(show_time(ModTime(it), 0), buff, bp); + safe_str(show_time(ModTime(it), utc), buff, bp); +} + +/* ARGSUSED */ +FUNCTION(fun_msecs) +{ + dbref it = match_thing(executor, args[0]); + if (!GoodObject(it) || IsGarbage(it)) + safe_str(T(e_notvis), buff, bp); + else if (!Can_Examine(executor, it) || IsPlayer(it)) + safe_str(T(e_perm), buff, bp); + else + safe_integer((intmax_t) ModTime(it), buff, bp); } /* ARGSUSED */ @@ -1980,7 +2042,13 @@ FUNCTION(fun_tel) /* ARGSUSED */ FUNCTION(fun_isdbref) { - safe_boolean(parse_dbref(args[0]) != NOTHING, buff, bp); + safe_boolean(parse_objid(args[0]) != NOTHING, buff, bp); +} + +/* ARGSUSED */ +FUNCTION(fun_isobjid) +{ + safe_boolean(is_objid(args[0]), buff, bp); } /* ARGSUSED */ diff --git a/src/funlist.c b/src/funlist.c index 6ead054..6a2814e 100644 --- a/src/funlist.c +++ b/src/funlist.c @@ -10,38 +10,28 @@ #include "config.h" #include #include -#include "ansi.h" #include "conf.h" #include "case.h" #include "externs.h" +#include "ansi.h" #include "parse.h" #include "boolexp.h" #include "function.h" #include "mymalloc.h" -#include "pcre.h" +#include "mypcre.h" #include "match.h" #include "attrib.h" #include "dbdefs.h" #include "flags.h" #include "mushdb.h" #include "lock.h" +#include "sort.h" #include "confmagic.h" -#define MAX_SORTSIZE (BUFFER_LEN / 2) /**< Maximum number of elements to sort */ static char *next_token(char *str, char sep); -static char *autodetect_list(char **ptrs, int nptrs); -static char *get_list_type(char **args, int nargs, - int type_pos, char **ptrs, int nptrs); -static char *get_list_type_noauto(char **args, int nargs, int type_pos); -static int i_comp(const void *s1, const void *s2); -static int f_comp(const void *s1, const void *s2); -static int u_comp(const void *s1, const void *s2); static int regrep_helper(dbref who, dbref what, dbref parent, char const *name, ATTR *atr, void *args); -/** Type definition for a qsort comparison function */ -typedef int (*comp_func) (const void *, const void *); -static void sane_qsort(void **array, int left, int right, comp_func compare); enum itemfun_op { IF_DELETE, IF_REPLACE, IF_INSERT }; static void do_itemfuns(char *buff, char **bp, char *str, char *num, char *word, char *sep, enum itemfun_op flag); @@ -53,6 +43,8 @@ int inum_limit = 0; /**< limit of iter depth */ int iter_break = 0; /**< iter break */ extern const unsigned char *tables; +#define RealGoodObject(x) (GoodObject(x) && !IsGarbage(x)) + static char * next_token(char *str, char sep) { @@ -98,7 +90,7 @@ list2arr_ansi(char *r[], int max, char *list, char sep) { first = 0; for (i = 0; p && (i < max); i++, p = split_token(&aptr, sep)) { lp = list; - safe_ansi_string2(as, p - (as->text), strlen(p), list, &lp); + safe_ansi_string(as, p - (as->text), strlen(p), list, &lp); *lp = '\0'; r[i] = mush_strdup(list, "list2arr_item"); } @@ -195,7 +187,7 @@ int elist2arr(char *r[], int max, char *list, char sep) { * \param sep string to use as separator between words. */ void -arr2list(char *r[], int max, char *list, char **lp, char *sep) +arr2list(char *r[], int max, char *list, char **lp, const char *sep) { int i; int seplen = 0; @@ -281,12 +273,12 @@ FUNCTION(fun_munge) /* Break up the two lists into their respective elements. */ - ptrs1 = (char **) mush_malloc(MAX_SORTSIZE * sizeof(char *), "ptrarray"); - ptrs2 = (char **) mush_malloc(MAX_SORTSIZE * sizeof(char *), "ptrarray"); + ptrs1 = mush_calloc(MAX_SORTSIZE, sizeof(char *), "ptrarray"); + ptrs2 = mush_calloc(MAX_SORTSIZE, sizeof(char *), "ptrarray"); /* ptrs3 is destructively modified, but it's a copy of ptrs2, so we * make it a straight copy of ptrs2 and freearr() on ptrs2. */ - ptrs3 = (char **) mush_malloc(MAX_SORTSIZE * sizeof(char *), "ptrarray"); + ptrs3 = mush_calloc(MAX_SORTSIZE, sizeof(char *), "ptrarray"); if (!ptrs1 || !ptrs2) mush_panic("Unable to allocate memory in fun_munge"); @@ -311,7 +303,7 @@ FUNCTION(fun_munge) uargs[0] = lp; uargs[1] = isep; do_userfn(rlist, &rp, thing, attrib, 2, uargs, - executor, caller, enactor, pe_info); + executor, caller, enactor, pe_info, 0); *rp = '\0'; /* Now that we have our result, put it back into array form. Search @@ -319,7 +311,7 @@ FUNCTION(fun_munge) * corresponding element from list2. Mark used elements with * NULL to handle duplicates */ - results = (char **) mush_malloc(MAX_SORTSIZE * sizeof(char *), "ptrarray"); + results = mush_calloc(MAX_SORTSIZE, sizeof(char *), "ptrarray"); if (!results) mush_panic("Unable to allocate memory in fun_munge"); nresults = list2arr_ansi(results, MAX_SORTSIZE, rlist, sep); @@ -372,8 +364,8 @@ FUNCTION(fun_elements) osep = osepd; } - ptrs = (char **) mush_malloc(MAX_SORTSIZE * sizeof(char *), "ptrarray"); - wordlist = (char *) mush_malloc(BUFFER_LEN, "string"); + ptrs = mush_calloc(MAX_SORTSIZE, sizeof(char *), "ptrarray"); + wordlist = mush_malloc(BUFFER_LEN, "string"); if (!ptrs || !wordlist) mush_panic("Unable to allocate memory in fun_elements"); @@ -682,483 +674,6 @@ FUNCTION(fun_shuffle) freearr(words, n); } -typedef enum { - L_NUMERIC, - L_FLOAT, - L_ALPHANUM, - L_DBREF -} ltype; - -static char * -autodetect_list(char *ptrs[], int nptrs) -{ - char * sort_type; - ltype lt; - int i; - - - lt = L_NUMERIC; - sort_type = NUMERIC_LIST; - - for (i = 0; i < nptrs; i++) { - switch (lt) { - case L_NUMERIC: - if (!is_strict_integer(ptrs[i])) { - /* If it's not an integer, see if it's a floating-point number */ - if (is_strict_number(ptrs[i])) { - lt = L_FLOAT; - sort_type = FLOAT_LIST; - } else if (i == 0) { - - /* If we get something non-numeric, switch to an - * alphanumeric guess, unless this is the first - * element and we have a dbref. - */ - if (is_objid(ptrs[i])) { - lt = L_DBREF; - sort_type = DBREF_LIST; - } else - return ALPHANUM_LIST; - } - } - break; - case L_FLOAT: - if (!is_strict_number(ptrs[i])) - return ALPHANUM_LIST; - break; - case L_DBREF: - if (!is_objid(ptrs[i])) - return ALPHANUM_LIST; - break; - default: - return ALPHANUM_LIST; - } - } - return sort_type; -} - - -typedef struct sort_record s_rec; - -typedef int (*qsort_func) (const void *, const void *); -typedef void (*makerecord) (s_rec *, dbref player, char *sortflags); - -#define GENRECORD(x) void x(s_rec *rec,dbref player,char *sortflags); \ - void x(s_rec *rec, \ - dbref player __attribute__ ((__unused__)), \ - char *sortflags __attribute__ ((__unused__))) - -/** Sorting strings by different values. We store both the string and - * its 'key' to sort by. Sort of a hardcode munge. - */ -struct sort_record { - char *ptr; /**< NULL except for sortkey */ - char *val; /**< The string this is */ - dbref db; /**< dbref (default 0, bad is -1) */ - char *str; /**< string comparisons */ - int num; /**< integer comparisons */ - NVAL numval; /**< float comparisons */ - int freestr; /**< free str on completion */ -}; - -/* Compare(r,x,y) { - * if (x->db < 0 && y->db < 0) - * return 0; // Garbage is identical. - * if (x->db < 0) - * return 2; // Garbage goes last. - * if (y->db < 0) - * return -2; // Garbage goes last. - * if (r < 0) - * return -2; // different - * if (r > 0) - * return 2; // different - * if (x->db < y->db) - * return -1; // similar - * if (y->db < x-db) - * return 1; // similar - * return 0; // identical - * } - */ - -/* If I could, I'd let sort() toss out non-existant dbrefs - * Instead, sort stuffs them into a jumble at the end. */ - -#define Compare(r,x,y) \ - ((x->db < 0 || y->db < 0) ? \ - ((x->db < 0 && y->db < 0) ? 0 : (x->db < 0 ? 2 : -2)) \ - : ((r != 0) ? (r < 0 ? -2 : 2) \ - : (x->db == y->db ? 0 : (x->db < y->db ? -1 : 1)) \ - ) \ - ) - -static int -s_comp(const void *s1, const void *s2) -{ - const s_rec *sr1 = (const s_rec *) s1; - const s_rec *sr2 = (const s_rec *) s2; - int res = 0; - res = strcoll(sr1->str, sr2->str); - return Compare(res, sr1, sr2); -} - -static int -si_comp(const void *s1, const void *s2) -{ - const s_rec *sr1 = (const s_rec *) s1; - const s_rec *sr2 = (const s_rec *) s2; - int res = 0; - res = strcasecoll(sr1->str, sr2->str); - return Compare(res, sr1, sr2); -} - -static int -i_comp(const void *s1, const void *s2) -{ - const s_rec *sr1 = (const s_rec *) s1; - const s_rec *sr2 = (const s_rec *) s2; - int res = 0; - res = sr1->num - sr2->num; - return Compare(res, sr1, sr2); -} - -static int -f_comp(const void *s1, const void *s2) -{ - const s_rec *sr1 = (const s_rec *) s1; - const s_rec *sr2 = (const s_rec *) s2; - NVAL res = 0; - res = sr1->numval - sr2->numval; - return Compare(res, sr1, sr2); -} - -GENRECORD(gen_alphanum) -{ - size_t len; - if (strchr(rec->val, ESC_CHAR)) { - rec->str = mush_strdup(remove_markup(rec->val, &len), "genrecord"); - rec->freestr = 1; - } else { - rec->str = rec->val; - } -} - -GENRECORD(gen_dbref) -{ - rec->num = qparse_dbref(rec->val); -} - -GENRECORD(gen_num) -{ - rec->num = parse_integer(rec->val); -} - -GENRECORD(gen_float) -{ - rec->numval = parse_number(rec->val); -} - -#define RealGoodObject(x) (GoodObject(x) && !IsGarbage(x)) - -GENRECORD(gen_db_name) -{ - rec->str = (char *) ""; - if (RealGoodObject(rec->db)) - rec->str = (char *) Name(rec->db); -} - -GENRECORD(gen_db_idle) -{ - rec->num = -1; - if (RealGoodObject(rec->db)) { - if (Priv_Who(player)) - rec->num = least_idle_time_priv(rec->db); - else - rec->num = least_idle_time(rec->db); - } -} - -GENRECORD(gen_db_conn) -{ - rec->num = -1; - if (RealGoodObject(rec->db)) { - if (Priv_Who(player)) - rec->num = most_conn_time_priv(rec->db); - else - rec->num = most_conn_time(rec->db); - } -} - -GENRECORD(gen_db_ctime) -{ - if (RealGoodObject(rec->db)) - rec->num = CreTime(rec->db); -} - -GENRECORD(gen_db_owner) -{ - if (RealGoodObject(rec->db)) - rec->num = Owner(rec->db); -} - -GENRECORD(gen_db_loc) -{ - rec->num = -1; - if (RealGoodObject(rec->db) && Can_Locate(player, rec->db)) { - rec->num = Location(rec->db); - } -} - -GENRECORD(gen_db_attr) -{ - /* Eek, I hate dealing with memory issues. */ - - static char *defstr = (char *) ""; - const char *ptr; - - rec->str = defstr; - if (RealGoodObject(rec->db) && sortflags && *sortflags && - (ptr = do_get_attrib(player, rec->db, sortflags)) != NULL) { - rec->str = mush_strdup(ptr, "genrecord"); - rec->freestr = 1; - } -} - -typedef struct _list_type_list_ { - char *name; - makerecord make_record; - qsort_func sorter; - int isdbs; -} list_type_list; - -char ALPHANUM_LIST[] = "A"; -char INSENS_ALPHANUM_LIST[] = "I"; -char DBREF_LIST[] = "D"; -char NUMERIC_LIST[] = "N"; -char FLOAT_LIST[] = "F"; -char DBREF_NAME_LIST[] = "NAME"; -char DBREF_NAMEI_LIST[] = "NAMEI"; -char DBREF_IDLE_LIST[] = "IDLE"; -char DBREF_CONN_LIST[] = "CONN"; -char DBREF_CTIME_LIST[] = "CTIME"; -char DBREF_OWNER_LIST[] = "OWNER"; -char DBREF_LOCATION_LIST[] = "LOC"; -char DBREF_ATTR_LIST[] = "ATTR"; -char DBREF_ATTRI_LIST[] = "ATTRI"; -char *UNKNOWN_LIST = NULL; - -list_type_list ltypelist[] = { - /* List type name, recordmaker, comparer, dbrefs? */ - {ALPHANUM_LIST, gen_alphanum, s_comp, 0}, - {INSENS_ALPHANUM_LIST, gen_alphanum, si_comp, 0}, - {DBREF_LIST, gen_dbref, i_comp, 0}, - {NUMERIC_LIST, gen_num, i_comp, 0}, - {FLOAT_LIST, gen_float, f_comp, 0}, - {DBREF_NAME_LIST, gen_db_name, s_comp, 1}, - {DBREF_NAMEI_LIST, gen_db_name, si_comp, 1}, - {DBREF_IDLE_LIST, gen_db_idle, i_comp, 1}, - {DBREF_CONN_LIST, gen_db_conn, i_comp, 1}, - {DBREF_CTIME_LIST, gen_db_ctime, i_comp, 1}, - {DBREF_OWNER_LIST, gen_db_owner, i_comp, 1}, - {DBREF_LOCATION_LIST, gen_db_loc, i_comp, 1}, - {DBREF_ATTR_LIST, gen_db_attr, s_comp, 1}, - {DBREF_ATTRI_LIST, gen_db_attr, si_comp, 1}, - /* This stops the loop, so is default */ - {NULL, gen_alphanum, s_comp, 0} -}; - -char * -get_list_type(char *args[], int nargs, int type_pos, char *ptrs[], int nptrs) -{ - static char stype[BUFFER_LEN]; - int i; - char *str; - if (nargs >= type_pos) { - str = args[type_pos - 1]; - if (*str) { - strcpy(stype, str); - str = strchr(stype, ':'); - if (str) - *(str++) = '\0'; - for (i = 0; ltypelist[i].name && strcasecmp(ltypelist[i].name, stype); - i++) ; - /* return ltypelist[i].name; */ - if (ltypelist[i].name) { - return args[type_pos - 1]; - } - } - } - return autodetect_list(ptrs, nptrs); -} - -char * -get_list_type_noauto(char *args[], int nargs, int type_pos) -{ - static char stype[BUFFER_LEN]; - int i; - char *str; - if (nargs >= type_pos) { - str = args[type_pos - 1]; - if (*str) { - strcpy(stype, str); - str = strchr(stype, ':'); - if (str) - *(str++) = '\0'; - for (i = 0; ltypelist[i].name && strcasecmp(ltypelist[i].name, stype); - i++) ; - /* return ltypelist[i].name; */ - return args[type_pos - 1]; - } - } - return UNKNOWN_LIST; -} - - -static dbref ucomp_executor, ucomp_caller, ucomp_enactor; -static char ucomp_buff[BUFFER_LEN]; -static PE_Info *ucomp_pe_info; - -static int -u_comp(const void *s1, const void *s2) -{ - char result[BUFFER_LEN], *rp; - char const *tbuf; - int n; - - /* Our two arguments are passed as %0 and %1 to the sortby u-function. */ - - /* Note that this function is for use in conjunction with our own - * sane_qsort routine, NOT with the standard library qsort! - */ - global_eval_context.wenv[0] = (char *) s1; - global_eval_context.wenv[1] = (char *) s2; - - /* Run the u-function, which should return a number. */ - - tbuf = ucomp_buff; - rp = result; - if (process_expression(result, &rp, &tbuf, - ucomp_executor, ucomp_caller, ucomp_enactor, - PE_DEFAULT, PT_DEFAULT, ucomp_pe_info)) - return 0; - n = parse_integer(result); - - return n; -} - -/** A generic comparer routine to compare two values of any sort type. - * \param - */ -int -gencomp(dbref player, char *a, char *b, char *sort_type) -{ - char *ptr; - int i, len; - int result; - s_rec s1, s2; - ptr = NULL; - if (!sort_type) { - /* Advance i to the default */ - for (i = 0; ltypelist[i].name; i++) ; - } else if ((ptr = strchr(sort_type, ':'))) { - len = ptr - sort_type; - ptr += 1; - if (!*ptr) - ptr = NULL; - for (i = 0; - ltypelist[i].name && strncasecmp(ltypelist[i].name, sort_type, len); - i++) ; - } else { - for (i = 0; ltypelist[i].name && strcasecmp(ltypelist[i].name, sort_type); - i++) ; - } - s1.freestr = s2.freestr = 0; - if (ltypelist[i].isdbs) { - s1.db = parse_dbref(a); - s2.db = parse_dbref(b); - if (!RealGoodObject(s1.db)) - s1.db = NOTHING; - if (!RealGoodObject(s2.db)) - s2.db = NOTHING; - } else { - s1.db = s2.db = 0; - } - - s1.val = a; - s2.val = b; - ltypelist[i].make_record(&s1, player, ptr); - ltypelist[i].make_record(&s2, player, ptr); - result = ltypelist[i].sorter((const void *) &s1, (const void *) &s2); - if (s1.freestr) - mush_free(s1.str, "genrecord"); - if (s2.freestr) - mush_free(s2.str, "genrecord"); - return result; -} - -/** A generic sort routine to sort several different - * types of arrays, in place. - * \param player the player executing the sort. - * \param s the array to sort. - * \param n number of elements in array s - * \param sort_type the string that describes the sort type. - */ - -void -do_gensort(dbref player, char *keys[], char *strs[], int n, char *sort_type) -{ - char *ptr; - static char stype[BUFFER_LEN]; - int i, sorti; - s_rec *sp; - ptr = NULL; - if (!sort_type || !*sort_type) { - /* Advance sorti to the default */ - for (sorti = 0; ltypelist[sorti].name; sorti++) ; - } else if (strchr(sort_type, ':') != NULL) { - strcpy(stype, sort_type); - ptr = strchr(stype, ':'); - *(ptr++) = '\0'; - if (!*ptr) - ptr = NULL; - for (sorti = 0; - ltypelist[sorti].name && strcasecmp(ltypelist[sorti].name, stype); - sorti++) ; - } else { - for (sorti = 0; - ltypelist[sorti].name && strcasecmp(ltypelist[sorti].name, sort_type); - sorti++) ; - } - sp = (s_rec *) mush_malloc(n * sizeof(s_rec), "do_gensort"); - for (i = 0; i < n; i++) { - sp[i].val = keys[i]; - sp[i].freestr = 0; - sp[i].db = 0; - if (strs) { - sp[i].ptr = strs[i]; - } else { - sp[i].ptr = NULL; - } - sp[i].str = NULL; - if (ltypelist[sorti].isdbs) { - sp[i].db = parse_objid(keys[i]); - if (!RealGoodObject(sp[i].db)) - sp[i].db = NOTHING; - } - ltypelist[sorti].make_record(&(sp[i]), player, ptr); - } - qsort((void *) sp, n, sizeof(s_rec), ltypelist[sorti].sorter); - - for (i = 0; i < n; i++) { - keys[i] = sp[i].val; - if (strs) { - strs[i] = sp[i].ptr; - } - if (sp[i].freestr) - mush_free(sp[i].str, "genrecord"); - } - mush_free((Malloc_t) sp, "do_gensort"); -} - /* ARGSUSED */ FUNCTION(fun_sort) { @@ -1187,70 +702,6 @@ FUNCTION(fun_sort) freearr(ptrs, nptrs); } -static void -sane_qsort(void *array[], int left, int right, comp_func compare) -{ - /* Andrew Molitor's qsort, which doesn't require transitivity between - * comparisons (essential for preventing crashes due to boneheads - * who write comparison functions where a > b doesn't mean b < a). - */ - /* Actually, this sort doesn't require commutivity. - * Sorting doesn't make sense without transitivity... - */ - - int i, last; - void *tmp; - -loop: - if (left >= right) - return; - - /* Pick something at random at swap it into the leftmost slot */ - /* This is the pivot, we'll put it back in the right spot later */ - - i = get_random_long(left, right); - tmp = array[i]; - array[i] = array[left]; - array[left] = tmp; - - last = left; - for (i = left + 1; i <= right; i++) { - - /* Walk the array, looking for stuff that's less than our */ - /* pivot. If it is, swap it with the next thing along */ - - if (compare(array[i], array[left]) < 0) { - last++; - if (last == i) - continue; - - tmp = array[last]; - array[last] = array[i]; - array[i] = tmp; - } - } - - /* Now we put the pivot back, it's now in the right spot, we never */ - /* need to look at it again, trust me. */ - - tmp = array[last]; - array[last] = array[left]; - array[left] = tmp; - - /* At this point everything underneath the 'last' index is < the */ - /* entry at 'last' and everything above it is not < it. */ - - if ((last - left) < (right - last)) { - sane_qsort(array, left, last - 1, compare); - left = last + 1; - goto loop; - } else { - sane_qsort(array, last + 1, right, compare); - right = last - 1; - goto loop; - } -} - /* ARGSUSED */ FUNCTION(fun_sortkey) { @@ -1302,6 +753,13 @@ FUNCTION(fun_sortkey) } } + +/* From sort.c */ +extern dbref ucomp_executor, ucomp_caller, ucomp_enactor; +extern char ucomp_buff[BUFFER_LEN]; +extern PE_Info *ucomp_pe_info; + + /* ARGSUSED */ FUNCTION(fun_sortby) { @@ -1375,8 +833,8 @@ FUNCTION(fun_setinter) if (!delim_check(buff, bp, nargs, args, 3, &sep)) return; - a1 = (char **) mush_malloc(MAX_SORTSIZE * sizeof(char *), "ptrarray"); - a2 = (char **) mush_malloc(MAX_SORTSIZE * sizeof(char *), "ptrarray"); + a1 = mush_calloc(MAX_SORTSIZE, sizeof(char *), "ptrarray"); + a2 = mush_calloc(MAX_SORTSIZE, sizeof(char *), "ptrarray"); if (!a1 || !a2) mush_panic("Unable to allocate memory in fun_setinter"); @@ -1505,8 +963,8 @@ FUNCTION(fun_setunion) if (!delim_check(buff, bp, nargs, args, 3, &sep)) return; - a1 = (char **) mush_malloc(MAX_SORTSIZE * sizeof(char *), "ptrarray"); - a2 = (char **) mush_malloc(MAX_SORTSIZE * sizeof(char *), "ptrarray"); + a1 = mush_calloc(MAX_SORTSIZE, sizeof(char *), "ptrarray"); + a2 = mush_calloc(MAX_SORTSIZE, sizeof(char *), "ptrarray"); if (!a1 || !a2) mush_panic("Unable to allocate memory in fun_diff"); @@ -1643,8 +1101,8 @@ FUNCTION(fun_setdiff) if (!delim_check(buff, bp, nargs, args, 3, &sep)) return; - a1 = (char **) mush_malloc(MAX_SORTSIZE * sizeof(char *), "ptrarray"); - a2 = (char **) mush_malloc(MAX_SORTSIZE * sizeof(char *), "ptrarray"); + a1 = mush_calloc(MAX_SORTSIZE, sizeof(char *), "ptrarray"); + a2 = mush_calloc(MAX_SORTSIZE, sizeof(char *), "ptrarray"); if (!a1 || !a2) mush_panic("Unable to allocate memory in fun_diff"); @@ -1764,7 +1222,7 @@ FUNCTION(fun_unique) if (!delim_check(buff, bp, nargs, args, 3, &sep)) return; - a1 = (char **) mush_malloc(MAX_SORTSIZE * sizeof(char *), "ptrarray"); + a1 = mush_calloc(MAX_SORTSIZE, sizeof(char *), "ptrarray"); if (!a1) mush_panic("Unable to allocate memory in fun_unique"); @@ -1772,7 +1230,7 @@ FUNCTION(fun_unique) /* make array out of the list */ n1 = list2arr_ansi(a1, MAX_SORTSIZE, args[0], sep); - a2 = mush_malloc(n1 * sizeof(char *), "ptrarray"); + a2 = mush_calloc(n1, sizeof(char *), "ptrarray"); if (!a2) mush_panic("Unable to allocate memory in fun_unique"); @@ -1847,18 +1305,18 @@ FUNCTION(fun_lnum) return; } } else { - if (end == 0) + if (end == 0.0) return; /* Special case - lnum(0) -> blank string */ - else if (end == 1) { + else if (end == 1.0) { safe_str("0", buff, bp); /* Special case - lnum(1) -> 0 */ return; } end--; - if (end < 0) { + if (end < 0.0) { safe_str(T("#-1 NUMBER OUT OF RANGE"), buff, bp); return; } - start = 0; + start = 0.0; } if (nargs > 2) { osep = args[2]; @@ -2042,7 +1500,7 @@ FUNCTION(fun_namegraball) if (!delim_check(buff, bp, nargs, args, 3, &sep)) return; - absolute = parse_dbref(args[1]); + absolute = parse_objid(args[1]); if (!RealGoodObject(absolute)) absolute = NOTHING; @@ -2050,7 +1508,7 @@ FUNCTION(fun_namegraball) s = trim_space_sep(args[0], sep); do { r = split_token(&s, sep); - victim = parse_dbref(r); + victim = parse_objid(r); if (!RealGoodObject(victim)) continue; /* Don't bother with garbage */ if (!(string_match(Name(victim), args[1]) || (absolute == victim))) @@ -2068,7 +1526,7 @@ FUNCTION(fun_namegraball) s = trim_space_sep(args[0], sep); do { r = split_token(&s, sep); - victim = parse_dbref(r); + victim = parse_objid(r); if (!RealGoodObject(victim)) continue; /* Don't bother with garbage */ if (!can_interact(victim, executor, INTERACT_MATCH)) @@ -2099,7 +1557,7 @@ FUNCTION(fun_namegrab) if (!delim_check(buff, bp, nargs, args, 3, &sep)) return; - absolute = parse_dbref(args[1]); + absolute = parse_objid(args[1]); if (!RealGoodObject(absolute)) absolute = NOTHING; @@ -2107,7 +1565,7 @@ FUNCTION(fun_namegrab) s = trim_space_sep(args[0], sep); do { r = split_token(&s, sep); - victim = parse_dbref(r); + victim = parse_objid(r); if (!RealGoodObject(victim)) continue; /* Don't bother with garbage */ /* Dbref match has top priority */ @@ -2143,15 +1601,19 @@ FUNCTION(fun_match) char *s, *r; char sep; int wcount = 1; + size_t len; + char needle[BUFFER_LEN]; if (!delim_check(buff, bp, nargs, args, 3, &sep)) return; + strncpy(needle, remove_markup(args[1], &len), BUFFER_LEN); + /* Walk the wordstring, until we find the word we want. */ - s = trim_space_sep(args[0], sep); + s = trim_space_sep(remove_markup(args[0], &len), sep); do { r = split_token(&s, sep); - if (quick_wild(args[1], r)) { + if (quick_wild(needle, r)) { safe_integer(wcount, buff, bp); return; } @@ -2536,9 +1998,64 @@ do_itemfuns(char *buff, char **bp, char *str, char *num, char *word, /* ARGSUSED */ FUNCTION(fun_ldelete) { - /* delete a word at position X of a list */ + /* delete a word at given positions of a list */ + + /* Given a list and a list of numbers, delete the corresponding + * elements of the list. elements(ack bar eep foof yay,2 4) = bar foof + * A separator for the first list is allowed. + * This code modified slightly from 'elements' + */ + int nwords, cur; + char **ptrs; + char *wordlist; + int first = 0; + char *s, *r, sep; + char *osep, osepd[2] = { '\0', '\0' }; + + if (!delim_check(buff, bp, nargs, args, 3, &sep)) + return; - do_itemfuns(buff, bp, args[0], args[1], NULL, args[2], IF_DELETE); + if (nargs == 4) + osep = args[3]; + else { + osepd[0] = sep; + osep = osepd; + } + + ptrs = mush_calloc(MAX_SORTSIZE, sizeof(char *), "ptrarray"); + wordlist = mush_malloc(BUFFER_LEN, "string"); + if (!ptrs || !wordlist) + mush_panic("Unable to allocate memory in fun_elements"); + + /* Turn the first list into an array. */ + strcpy(wordlist, args[0]); + nwords = list2arr_ansi(ptrs, MAX_SORTSIZE, wordlist, sep); + + s = trim_space_sep(args[1], ' '); + + /* Go through the second list, grabbing the numbers and finding the + * corresponding elements. + */ + do { + r = split_token(&s, ' '); + cur = atoi(r) - 1; + if ((cur >= 0) && (cur < nwords)) { + ptrs[cur] = NULL; + } + } while (s); + for (cur = 0; cur < nwords; cur++) { + if (ptrs[cur]) { + if (first) + safe_str(osep, buff, bp); + else + first = 1; + safe_str(ptrs[cur], buff, bp); + } + } + + freearr(ptrs, nwords); + mush_free((Malloc_t) ptrs, "ptrarray"); + mush_free((Malloc_t) wordlist, "string"); } /* ARGSUSED */ @@ -2589,31 +2106,47 @@ FUNCTION(fun_member) /* ARGSUSED */ FUNCTION(fun_before) { - char *p; + const char *p, *q; + ansi_string *as; + size_t len; + p = remove_markup(args[1], &len); - if (!*args[1]) - p = strchr(args[0], ' '); - else - p = strstr(args[0], args[1]); - if (p) { - safe_strl(args[0], p - args[0], buff, bp); - } else + if (!*p) + p = " "; + as = parse_ansi_string(args[0]); + q = strstr(as->text, p); + if (q) { + safe_ansi_string(as, 0, q - as->text, buff, bp); + } else { safe_strl(args[0], arglens[0], buff, bp); + } + free_ansi_string(as); } /* ARGSUSED */ FUNCTION(fun_after) { - char *p; + ansi_string *as; + char *p, *delim; + size_t len, count; + size_t start; if (!*args[1]) { args[1][0] = ' '; args[1][1] = '\0'; arglens[1] = 1; } - p = strstr(args[0], args[1]); - if (p) - safe_str(p + arglens[1], buff, bp); + delim = remove_markup(args[1], &len); + len--; + as = parse_ansi_string(args[0]); + + p = strstr(as->text, delim); + if (p) { + start = p - as->text + len; + count = as->len - start; + safe_ansi_string(as, start, count, buff, bp); + } + free_ansi_string(as); } /* ARGSUSED */ @@ -2634,11 +2167,11 @@ FUNCTION(fun_revwords) osep = osepd; } - words = (char **) mush_malloc(sizeof(char *) * BUFFER_LEN, "wordlist"); + words = mush_calloc(BUFFER_LEN, sizeof(char *), "wordlist"); origcount = count = list2arr_ansi(words, BUFFER_LEN, args[0], sep); if (count == 0) { - mush_free((Malloc_t) words, "wordlist"); + mush_free(words, "wordlist"); return; } @@ -2648,7 +2181,7 @@ FUNCTION(fun_revwords) safe_str(words[--count], buff, bp); } freearr(words, origcount); - mush_free((Malloc_t) words, "wordlist"); + mush_free(words, "wordlist"); } /* ARGSUSED */ @@ -2665,41 +2198,57 @@ FUNCTION(fun_words) FUNCTION(fun_splice) { /* like MERGE(), but does it for a word */ - - char *s0, *s1, *s2; - char *p0, *p1; + char **orig; + char **repl; + char haystack[BUFFER_LEN]; + int ocount, rcount; + int i; char sep; + char osep[2]; if (!delim_check(buff, bp, nargs, args, 4, &sep)) return; - s0 = trim_space_sep(args[0], sep); - s1 = trim_space_sep(args[1], sep); - s2 = trim_space_sep(args[2], sep); + osep[0] = sep; + osep[1] = '\0'; - /* length checks */ - if (!*args[2]) { + orig = mush_calloc(MAX_SORTSIZE, sizeof(char *), "ptrarray"); + repl = mush_calloc(MAX_SORTSIZE, sizeof(char *), "ptrarray"); + /* Turn them into lists */ + ocount = list2arr(orig, MAX_SORTSIZE, args[0], sep); + rcount = list2arr(repl, MAX_SORTSIZE, args[1], sep); + + strncpy(haystack, remove_markup(args[2], NULL), BUFFER_LEN); + if (!*haystack) { safe_str(T("#-1 NEED A WORD"), buff, bp); + mush_free((Malloc_t) orig, "ptrarray"); + mush_free((Malloc_t) repl, "ptrarray"); return; } - if (do_wordcount(s2, sep) != 1) { + if (do_wordcount(haystack, sep) != 1) { safe_str(T("#-1 TOO MANY WORDS"), buff, bp); + mush_free((Malloc_t) orig, "ptrarray"); + mush_free((Malloc_t) repl, "ptrarray"); return; } - if (do_wordcount(s0, sep) != do_wordcount(s1, sep)) { + + if (ocount != rcount) { safe_str(T("#-1 NUMBER OF WORDS MUST BE EQUAL"), buff, bp); + mush_free((Malloc_t) orig, "ptrarray"); + mush_free((Malloc_t) repl, "ptrarray"); return; } - /* loop through the two lists */ - p0 = split_token(&s0, sep); - p1 = split_token(&s1, sep); - safe_str(strcmp(p0, s2) ? p0 : p1, buff, bp); - while (s0) { - p0 = split_token(&s0, sep); - p1 = split_token(&s1, sep); - safe_chr(sep, buff, bp); - safe_str(strcmp(p0, s2) ? p0 : p1, buff, bp); + + for (i = 0; i < ocount; i++) { + if (!ansi_strcmp(orig[i], haystack)) { + orig[i] = repl[i]; + } } + + arr2list(orig, ocount, buff, bp, osep); + + mush_free((Malloc_t) orig, "ptrarray"); + mush_free((Malloc_t) repl, "ptrarray"); } @@ -2867,7 +2416,7 @@ FUNCTION(fun_inum) return; } - safe_number(iter_place[inum - i], buff, bp); + safe_integer(iter_place[inum - i], buff, bp); } /* ARGSUSED */ @@ -3200,32 +2749,31 @@ FUNCTION(fun_table) /* string, regexp, replacement string. Acts like sed or perl's s///g, //with an ig version */ +/* TODO: Grab full function out of penn source */ FUNCTION(fun_regreplace) { pcre *re; - pcre_extra *study = NULL; + pcre_extra *extra, *study = NULL; const char *errptr; int subpatterns; int offsets[99]; int erroffset; + int flags = 0, all = 0, match_offset = 0; + struct re_save rsave; + + int i; const char *r, *obp; char *start, *oldbp; char tbuf[BUFFER_LEN], *tbp; - char abuf[BUFFER_LEN], *abp; - char prebuf[BUFFER_LEN], *prep; + char prebuf[BUFFER_LEN]; char postbuf[BUFFER_LEN], *postp; - pcre *old_re_code; - int flags = 0, all = 0, match_offset = 0, len, funccount; - int i; - - int old_re_subpatterns; - int *old_re_offsets; - char *old_re_from; - + ansi_string *orig, *repl; + int search; + int prelen; + size_t searchlen; + int funccount; - old_re_subpatterns = global_eval_context.re_subpatterns; - old_re_offsets = global_eval_context.re_offsets; - old_re_from = global_eval_context.re_from; + save_regexp_context(&rsave); if (called_as[strlen(called_as) - 1] == 'I') flags = PCRE_CASELESS; @@ -3233,59 +2781,81 @@ FUNCTION(fun_regreplace) if (string_prefix(called_as, "REGEDITALL")) all = 1; - abp = abuf; + /* Build orig */ + postp = postbuf; r = args[0]; - process_expression(abuf, &abp, &r, executor, caller, enactor, PE_DEFAULT, + process_expression(postbuf, &postp, &r, executor, caller, enactor, PE_DEFAULT, PT_DEFAULT, pe_info); - *abp = '\0'; - - postp = postbuf; - safe_str(abuf, postbuf, &postp); *postp = '\0'; + /* Ansi-less regedits */ for (i = 1; i < nargs - 1; i += 2) { - /* old postbuf is new prebuf */ - prep = prebuf; - safe_str(postbuf, prebuf, &prep); - *prep = '\0'; + /* If this string has ANSI, switch to using ansi only */ + if (strchr(postbuf, TAG_START)) + break; + + memcpy(prebuf, postbuf, BUFFER_LEN); + prelen = strlen(prebuf); + postp = postbuf; - *postp = '\0'; + + orig = parse_ansi_string(prebuf); + + /* Get the needle */ tbp = tbuf; r = args[i]; process_expression(tbuf, &tbp, &r, executor, caller, enactor, PE_DEFAULT, PT_DEFAULT, pe_info); *tbp = '\0'; - if ((re = pcre_compile(tbuf, flags, &errptr, &erroffset, tables)) == NULL) { + if ((re = pcre_compile(remove_markup(tbuf, &searchlen), + flags, &errptr, &erroffset, tables)) == NULL) { /* Matching error. */ safe_str(T("#-1 REGEXP ERROR: "), buff, bp); safe_str(errptr, buff, bp); + free_ansi_string(orig); + restore_regexp_context(&rsave); return; } - add_check("pcre"); - /* If we're going to match the pattern multiple times, let's - study it. */ + add_check("pcre"); /* re */ + if (searchlen) + searchlen--; + + /* If we're doing a lot, study the regexp to make sure it's good */ if (all) { study = pcre_study(re, 0, &errptr); if (errptr != NULL) { - mush_free((Malloc_t) re, "pcre"); + mush_free(re, "pcre"); safe_str(T("#-1 REGEXP ERROR: "), buff, bp); safe_str(errptr, buff, bp); + free_ansi_string(orig); + restore_regexp_context(&rsave); return; } if (study != NULL) + /* study */ add_check("pcre.extra"); } - len = strlen(prebuf); + + if (study) { + extra = study; + set_match_limit(extra); + } else + extra = default_match_limit(); + + search = 0; + /* Do all the searches and replaces we can */ + start = prebuf; - subpatterns = pcre_exec(re, study, prebuf, len, 0, 0, offsets, 99); + subpatterns = pcre_exec(re, extra, prebuf, prelen, 0, 0, offsets, 99); /* Match wasn't found... we're done */ if (subpatterns < 0) { safe_str(prebuf, postbuf, &postp); - mush_free((Malloc_t) re, "pcre"); + mush_free(re, "pcre"); + free_ansi_string(orig); if (study) - mush_free((Malloc_t) study, "pcre.extra"); + mush_free(study, "pcre.extra"); continue; } @@ -3298,11 +2868,10 @@ FUNCTION(fun_regreplace) prebuf[offsets[0]] = '\0'; safe_str(start, postbuf, &postp); prebuf[offsets[0]] = tmp; - /* Now copy in the replacement, putting in captured sub-expressions */ obp = args[i + 1]; global_eval_context.re_code = re; - global_eval_context.re_from = prebuf; + global_eval_context.re_from = orig; global_eval_context.re_offsets = offsets; global_eval_context.re_subpatterns = subpatterns; process_expression(postbuf, &postp, &obp, executor, caller, enactor, @@ -3319,26 +2888,121 @@ FUNCTION(fun_regreplace) /* Make sure we advance at least 1 char */ if (offsets[0] == match_offset) match_offset++; - } while (all && match_offset < len && (subpatterns = - pcre_exec(re, study, prebuf, len, - match_offset, 0, offsets, - 99)) >= 0); - + } while (all && match_offset < prelen && + (subpatterns = pcre_exec(re, extra, prebuf, prelen, + match_offset, 0, offsets, 99)) >= 0); - /* Now copy everything after the matched bit */ safe_str(start, postbuf, &postp); *postp = '\0'; - mush_free((Malloc_t) re, "pcre"); - if (study) - mush_free((Malloc_t) study, "pcre.extra"); - global_eval_context.re_code = old_re_code; - global_eval_context.re_offsets = old_re_offsets; - global_eval_context.re_subpatterns = old_re_subpatterns; - global_eval_context.re_from = old_re_from; + mush_free(re, "pcre"); + if (study != NULL) + mush_free(study, "pcre.extra"); + free_ansi_string(orig); } - safe_str(postbuf, buff, bp); + /* We get to this point if there is ansi in an 'orig' string */ + if (i < nargs - 1) { + + orig = parse_ansi_string(postbuf); + + /* For each search/replace pair, compare them against orig */ + for (; i < nargs - 1; i += 2) { + + /* Get the needle */ + tbp = tbuf; + r = args[i]; + process_expression(tbuf, &tbp, &r, executor, caller, enactor, PE_DEFAULT, + PT_DEFAULT, pe_info); + *tbp = '\0'; + + if ((re = pcre_compile(remove_markup(tbuf, &searchlen), + flags, &errptr, &erroffset, tables)) == NULL) { + /* Matching error. */ + safe_str(T("#-1 REGEXP ERROR: "), buff, bp); + safe_str(errptr, buff, bp); + free_ansi_string(orig); + restore_regexp_context(&rsave); + return; + } + add_check("pcre"); /* re */ + if (searchlen) + searchlen--; + + /* If we're doing a lot, study the regexp to make sure it's good */ + if (all) { + study = pcre_study(re, 0, &errptr); + if (errptr != NULL) { + mush_free(re, "pcre"); + safe_str(T("#-1 REGEXP ERROR: "), buff, bp); + safe_str(errptr, buff, bp); + free_ansi_string(orig); + restore_regexp_context(&rsave); + return; + } + if (study != NULL) + /* study */ + add_check("pcre.extra"); + } + if (study) { + extra = study; + set_match_limit(extra); + } else + extra = default_match_limit(); + + search = 0; + /* Do all the searches and replaces we can */ + do { + subpatterns = + pcre_exec(re, extra, orig->text, orig->len, search, 0, offsets, 99); + if (subpatterns >= 0) { + /* We have a match */ + /* Process the replacement */ + r = args[i + 1]; + global_eval_context.re_code = re; + global_eval_context.re_from = orig; + global_eval_context.re_offsets = offsets; + global_eval_context.re_subpatterns = subpatterns; + tbp = tbuf; + process_expression(tbuf, &tbp, &r, executor, caller, enactor, + PE_DEFAULT | PE_DOLLAR, PT_DEFAULT, pe_info); + *tbp = '\0'; + if (offsets[0] >= search) { + repl = parse_ansi_string(tbuf); + + /* Do the replacement */ + ansi_string_replace(orig, offsets[0], offsets[1] - offsets[0], + repl); + + /* Advance search */ + if (search == offsets[1]) { + search = offsets[0] + repl->len; + search++; + } else { + search = offsets[0] + repl->len; + } + /* if (offsets[0] < 1) search++; */ + + free_ansi_string(repl); + if (search >= orig->len) + break; + } else { + break; + } + } + } while (subpatterns >= 0 && all); + mush_free(re, "pcre"); + if (study != NULL) + mush_free(study, "pcre.extra"); + } + safe_ansi_string(orig, 0, orig->len, buff, bp); + free_ansi_string(orig); + } else { + safe_str(postbuf, buff, bp); + } + + restore_regexp_context(&rsave); + } /** array of indexes for %q registers during regexp matching */ @@ -3356,31 +3020,45 @@ FUNCTION(fun_regmatch) * */ int i, nqregs, curq; - char *qregs[NUMQ]; + char *qregs[NUMQ], *holder[NUMQ]; pcre *re; + pcre_extra *extra; const char *errptr; int erroffset; int offsets[99]; int subpatterns; int flags = 0; int qindex; + ansi_string *as; + char *txt; + char *qptr; + char *needle; + size_t len; if (strcmp(called_as, "REGMATCHI") == 0) flags = PCRE_CASELESS; + needle = remove_markup(args[1], &len); + + as = parse_ansi_string(args[0]); + txt = as->text; if (nargs == 2) { /* Don't care about saving sub expressions */ - safe_boolean(quick_regexp_match(args[1], args[0], flags ? 0 : 1), buff, bp); + safe_boolean(quick_regexp_match(needle, txt, flags ? 0 : 1), buff, bp); + free_ansi_string(as); return; } - if ((re = pcre_compile(args[1], flags, &errptr, &erroffset, tables)) == NULL) { + if ((re = pcre_compile(needle, flags, &errptr, &erroffset, tables)) == NULL) { /* Matching error. */ safe_str(T("#-1 REGEXP ERROR: "), buff, bp); safe_str(errptr, buff, bp); + free_ansi_string(as); return; } add_check("pcre"); - subpatterns = pcre_exec(re, NULL, args[0], arglens[0], 0, 0, offsets, 99); + extra = default_match_limit(); + + subpatterns = pcre_exec(re, extra, txt, arglens[0], 0, 0, offsets, 99); safe_integer(subpatterns >= 0, buff, bp); /* We need to parse the list of registers. Anything that we don't parse @@ -3391,6 +3069,36 @@ FUNCTION(fun_regmatch) if (subpatterns == 0) subpatterns = 33; nqregs = list2arr(qregs, NUMQ, args[2], ' '); + + /* Initialize every q-register used to '' */ + for (i = 0; i < nqregs; i++) { + char *regname; + char *named_subpattern = NULL; + int subpattern = 0; + holder[i] = mush_strdup(qregs[i], "regmatch"); + if ((regname = strchr(holder[i], ':'))) { + /* subexpr:register */ + *regname++ = '\0'; + if (is_strict_integer(holder[i])) + subpattern = parse_integer(holder[i]); + else + named_subpattern = holder[i]; + } else { + /* Get subexper by position in list */ + subpattern = i; + regname = holder[i]; + } + + if (regname && regname[0] && !regname[1] && + ((qindex = qreg_indexes[(unsigned char) regname[0]]) != -1)) + curq = qindex; + else + curq = -1; + if (curq < 0 || curq >= NUMQ) + continue; + *(global_eval_context.renv[curq]) = '\0'; + } + /* Now, only for those that have a pattern, copy text */ for (i = 0; i < nqregs; i++) { char *regname; char *named_subpattern = NULL; @@ -3416,17 +3124,29 @@ FUNCTION(fun_regmatch) if (curq < 0 || curq >= NUMQ) continue; - if (subpatterns < 0) + if (subpatterns < 0) { global_eval_context.renv[curq][0] = '\0'; - else if (named_subpattern) - pcre_copy_named_substring(re, args[0], offsets, subpatterns, - named_subpattern, - global_eval_context.renv[curq], BUFFER_LEN); - else - pcre_copy_substring(args[0], offsets, subpatterns, subpattern, - global_eval_context.renv[curq], BUFFER_LEN); + } else if (named_subpattern) { + qptr = global_eval_context.renv[curq]; + ansi_pcre_copy_named_substring(re, as, offsets, subpatterns, + named_subpattern, 1, + global_eval_context.renv[curq], &qptr); + + if (qptr != global_eval_context.renv[curq]) + *qptr = '\0'; + } else { + qptr = global_eval_context.renv[curq]; + ansi_pcre_copy_substring(as, offsets, subpatterns, subpattern, 1, + global_eval_context.renv[curq], &qptr); + if (qptr != global_eval_context.renv[curq]) + *qptr = '\0'; + } } - mush_free((Malloc_t) re, "pcre"); + for (i = 0; i < nqregs; i++) { + mush_free(holder[i], "regmatch"); + } + mush_free(re, "pcre"); + free_ansi_string(as); } @@ -3447,8 +3167,9 @@ FUNCTION(fun_regrep) const char *errptr; int erroffset; int flags = 0; - + bool free_study; dbref it = match_thing(executor, args[0]); + reharg.first = 0; if (it == NOTHING || it == AMBIGUOUS) { safe_str(T(e_notvis), buff, bp); @@ -3483,15 +3204,21 @@ FUNCTION(fun_regrep) mush_free(reharg.re, "pcre"); return; } - if (reharg.study) + if (reharg.study) { add_check("pcre.extra"); + free_study = true; + set_match_limit(reharg.study); + } else { + free_study = false; + reharg.study = default_match_limit(); + } reharg.buff = buff; reharg.bp = bp; atr_iter_get(executor, it, args[1], 0, regrep_helper, (void *) &reharg); mush_free(reharg.re, "pcre"); - if (reharg.study) + if (free_study) mush_free(reharg.study, "pcre.extra"); } @@ -3504,10 +3231,11 @@ regrep_helper(dbref who __attribute__ ((__unused__)), { struct regrep_data *reharg = args; char const *str; + size_t slen; int offsets[99]; - str = atr_value(atr); - if (pcre_exec(reharg->re, reharg->study, str, strlen(str), 0, 0, offsets, 99) + str = remove_markup(atr_value(atr), &slen); + if (pcre_exec(reharg->re, reharg->study, str, slen - 1, 0, 0, offsets, 99) >= 0) { if (reharg->first != 0) safe_chr(' ', reharg->buff, reharg->bp); @@ -3524,8 +3252,9 @@ regrep_helper(dbref who __attribute__ ((__unused__)), FUNCTION(fun_regrab) { char *r, *s, *b, sep; + size_t rlen; pcre *re; - pcre_extra *study; + pcre_extra *study, *extra; const char *errptr; int erroffset; int offsets[99]; @@ -3566,12 +3295,16 @@ FUNCTION(fun_regrab) mush_free(re, "pcre"); return; } - if (study) + if (study) { add_check("pcre.extra"); + extra = study; + set_match_limit(extra); + } else + extra = default_match_limit(); do { - r = split_token(&s, sep); - if (pcre_exec(re, study, r, strlen(r), 0, 0, offsets, 99) >= 0) { + r = remove_markup(split_token(&s, sep), &rlen); + if (pcre_exec(re, extra, r, rlen - 1, 0, 0, offsets, 99) >= 0) { if (all && *bp != b) safe_str(osep, buff, bp); safe_str(r, buff, bp); @@ -3580,9 +3313,9 @@ FUNCTION(fun_regrab) } } while (s); - mush_free((Malloc_t) re, "pcre"); + mush_free(re, "pcre"); if (study) - mush_free((Malloc_t) study, "pcre.extra"); + mush_free(study, "pcre.extra"); } FUNCTION(fun_apply) diff --git a/src/funmath.c b/src/funmath.c index 01e415d..a54fd18 100644 --- a/src/funmath.c +++ b/src/funmath.c @@ -12,11 +12,11 @@ #include #include #include +#include #include "conf.h" #include "externs.h" - +#include "sort.h" #include "parse.h" -#include "htab.h" #include "confmagic.h" #ifdef WIN32 @@ -33,86 +33,125 @@ static void do_spellnum(char *num, unsigned int len, char **buff, char ***bp); static void do_ordinalize(char **buff, char ***bp); -static int nval_sort(const void *, const void *); static NVAL find_median(NVAL *, int); -/** 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) - -HASHTAB htab_math; /**< Math function hash table */ - -/** A math function. */ -typedef struct { - const char *name; /**< Name of the function. */ - void (*func) (char **, int, char *, char **); /**< Pointer to function code. */ -} MATH; - -static void math_hash_insert(const char *, MATH *); -static MATH *math_hash_lookup(char *); static NVAL angle_to_rad(NVAL angle, const char *from); static NVAL rad_to_angle(NVAL angle, const char *to); static double frac(double v, double *RESTRICT n, double *RESTRICT d, double error); -void init_math_hashtab(void); -extern int format_long(long n, char *buff, char **bp, int maxlen, - int base); +int format_long(intmax_t n, char *buff, char **bp, int maxlen, int base); + extern int roman_numeral_table[256]; -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); +/* Generated by gperf */ +#include "lmathtab.c" +/* Functions for testing and parsing IVALs and UIVALs, the types of + * arguments to math functions that work on integers instead of + * floating-point numbers. No matter what IVAL is (32-bit or 64-bit), + * they can be passed to safe_integer()/safe_uinteger(). + * + * Math functions that operate on IVALs: div(), floordiv(), modulo(), + * remainder() + * Math functions that operate on UIVALS: shl(), shr(), band(), bnot(), bor() + * bxor(), bnand() + * + * Other functions work on NVALs or accept plain ints + */ -/* ARGSUSED */ -FUNCTION(fun_romantoarabic) { - int arabic; +static IVAL +parse_ival_full(const char *str, char **end, int base) +{ +#if SIZEOF_IVAL == 4 + return parse_int32(str, end, base); +#else +#error "Unsupported IVAL size" +#endif +} - arabic = RomanToArabic(args[0]); +static IVAL +parse_ival(const char *str) +{ + return parse_ival_full(str, NULL, 10); +} - if(arabic != -1) - safe_number(arabic, buff, bp); - else - safe_str(T(e_range), buff, bp); +static UIVAL +parse_uival_full(const char *str, char **end, int base) +{ +#if SIZEOF_IVAL == 4 + return parse_uint32(str, end, base); +#else +#error "Unsupported IVAL size" +#endif } -/* ARGSUSED */ -FUNCTION(fun_arabictoroman) { - char *roman_num; - - if (!is_number(args[0])) { - safe_str(T(e_num), buff, bp); - return; - } +static UIVAL +parse_uival(const char *str) +{ + return parse_uival_full(str, NULL, 10); +} - roman_num = ArabicToRoman(parse_integer(args[0])); - if(roman_num == NULL) - safe_str(T(e_range), buff, bp); - else - safe_str(roman_num, buff, bp); +/** Is string an integer suitable for a math function? + * To TinyMUSH, any string is an integer. To PennMUSH, a string that + * passes strtol is an integer, and a blank string is an integer + * if NULL_EQ_ZERO is turned on. + * \param str string to check. + * \retval 1 string is an integer. + * \retval 0 string is not an integer. + */ +static bool +is_ival(char const *str) +{ + char *end; + /* If we're emulating Tiny, anything is an integer */ + if (TINY_MATH) + return 1; + if (!str) + return 0; + while (isspace((unsigned char) *str)) + str++; + if (*str == '\0') + return NULL_EQ_ZERO; + errno = 0; + parse_ival_full(str, &end, 10); + if (errno == ERANGE || *end != '\0') + return 0; + return 1; +} + +/** Is string a UIVAL? + * To TinyMUSH, any string is an uinteger. To PennMUSH, a string that + * passes strtoul is an uinteger, and a blank string is an uinteger + * if NULL_EQ_ZERO is turned on. + * \param str string to check. + * \retval 1 string is an uinteger. + * \retval 0 string is not an uinteger. + */ +static bool +is_uival(char const *str) +{ + char *end; + + /* If we're emulating Tiny, anything is an integer */ + if (TINY_MATH) + return 1; + if (!str) + return 0; + /* strtoul() accepts negative numbers, so we still have to do this check */ + while (isspace((unsigned char) *str)) + str++; + if (*str == '\0') + return NULL_EQ_ZERO; + if (!(isdigit((unsigned char) *str) || *str == '+')) + return 0; + errno = 0; + parse_uival_full(str, &end, 10); + if (errno == ERANGE || *end != '\0') + return 0; + return 1; } /* ARGSUSED */ @@ -248,23 +287,21 @@ FUNCTION(fun_sign) /* ARGSUSED */ FUNCTION(fun_shl) { - if (!is_uinteger(args[0]) || !is_uinteger(args[1])) { + if (!is_uival(args[0]) || !is_uival(args[1])) { safe_str(T(e_uints), buff, bp); return; } - safe_uinteger(parse_uinteger(args[0]) << parse_uinteger(args[1]), buff, - bp); + safe_uinteger(parse_uival(args[0]) << parse_uival(args[1]), buff, bp); } /* ARGSUSED */ FUNCTION(fun_shr) { - if (!is_uinteger(args[0]) || !is_uinteger(args[1])) { + if (!is_uival(args[0]) || !is_uival(args[1])) { safe_str(T(e_uints), buff, bp); return; } - safe_uinteger(parse_uinteger(args[0]) >> parse_uinteger(args[1]), buff, - bp); + safe_uinteger(parse_uival(args[0]) >> parse_uival(args[1]), buff, bp); } /* ARGSUSED */ @@ -299,9 +336,14 @@ FUNCTION(fun_inc) } p--; } - /* p now points to the last non-numeric character in the string - * Move it to the first numeric character - */ + /* p now points to the last non-numeric character in the string */ + if (p == args[0] && (isdigit((unsigned char) *p) || (*p == '-'))) { + /* Special case - it's all digits, but out of range. */ + safe_str(T(e_range), buff, bp); + return; + } + + /* Move it to the first numeric character */ p++; num = parse_integer(p) + 1; *p = '\0'; @@ -321,8 +363,8 @@ FUNCTION(fun_dec) } /* Handle a null string */ if (!*args[0]) { - safe_str(NULL_EQ_ZERO ? "-1" : - T("#-1 ARGUMENT MUST END IN AN INTEGER"), buff, bp); + safe_str(NULL_EQ_ZERO ? "-1" : T("#-1 ARGUMENT MUST END IN AN INTEGER"), + buff, bp); return; } p = args[0] + arglens[0] - 1; @@ -341,9 +383,13 @@ FUNCTION(fun_dec) } p--; } - /* p now points to the last non-numeric character in the string - * Move it to the first numeric character - */ + /* p now points to the last non-numeric character in the string */ + if (p == args[0] && (isdigit((unsigned char) *p) || (*p == '-'))) { + /* Special case - it's all digits, but out of range. */ + safe_str(T(e_range), buff, bp); + return; + } + /* Move it to the first numeric character */ p++; num = parse_integer(p) - 1; *p = '\0'; @@ -399,49 +445,12 @@ FUNCTION(fun_abs) /* ARGSUSED */ FUNCTION(fun_dist2d) { - NVAL d1, d2, r; - - if (!is_number(args[0]) || !is_number(args[1]) || - !is_number(args[2]) || !is_number(args[3])) { - safe_str(T(e_nums), buff, bp); - return; - } - d1 = parse_number(args[0]) - parse_number(args[2]); - d2 = parse_number(args[1]) - parse_number(args[3]); - r = d1 * d1 + d2 * d2; -#ifndef HAS_IEEE_MATH - /* You can overflow, which is bad. */ - if (r < 0) { - safe_str(T("#-1 OVERFLOW ERROR"), buff, bp); - return; - } -#endif - safe_number(sqrt(r), buff, bp); + math_dist2d(args, nargs, buff, bp); } -/* ARGSUSED */ FUNCTION(fun_dist3d) { - NVAL d1, d2, d3, r; - - if (!is_number(args[0]) || !is_number(args[1]) || - !is_number(args[2]) || !is_number(args[3]) || - !is_number(args[4]) || !is_number(args[5])) { - safe_str(T(e_nums), buff, bp); - return; - } - d1 = parse_number(args[0]) - parse_number(args[3]); - d2 = parse_number(args[1]) - parse_number(args[4]); - d3 = parse_number(args[2]) - parse_number(args[5]); - r = d1 * d1 + d2 * d2 + d3 * d3; -#ifndef HAS_IEEE_MATH - /* You can overflow, which is bad. */ - if (r < 0) { - safe_str(T("#-1 OVERFLOW ERROR"), buff, bp); - return; - } -#endif - safe_number(sqrt(r), buff, bp); + math_dist3d(args, nargs, buff, bp); } /* ------------------------------------------------------------------------ @@ -675,8 +684,8 @@ FUNCTION(fun_vmul) while (p1 && p2) { safe_chr(sep, buff, bp); safe_number - (parse_number(split_token(&p1, sep)) * - parse_number(split_token(&p2, sep)), buff, bp); + (parse_number(split_token(&p1, sep)) * + parse_number(split_token(&p2, sep)), buff, bp); } /* make sure vectors were the same length */ if (p1 || p2) { @@ -716,7 +725,7 @@ FUNCTION(fun_vdot) product = 0; while (p1 && p2) { product += parse_number(split_token(&p1, sep)) * - parse_number(split_token(&p2, sep)); + parse_number(split_token(&p2, sep)); } if (p1 || p2) { safe_str(T("#-1 VECTORS MUST BE SAME DIMENSIONS"), buff, bp); @@ -891,16 +900,25 @@ FUNCTION(fun_ceil) safe_number(ceil(parse_number(args[0])), buff, bp); } +double +fround(double n, int d) +{ + double ex = pow(10.0, d); + return floor(n * ex + 0.5) / ex; +} + /* ARGSUSED */ FUNCTION(fun_round) { - char temp[BUFFER_LEN]; int places; + double n, rounded; if (!is_number(args[0])) { safe_str(T(e_num), buff, bp); return; - } + } else + n = parse_number(args[0]); + if (nargs == 2) { if (!is_integer(args[1])) { safe_str(T(e_int), buff, bp); @@ -915,15 +933,16 @@ FUNCTION(fun_round) else if (places > FLOAT_PRECISION) places = FLOAT_PRECISION; - /* The 0.0000001 is a kludge because .15 gets represented as .149999... - * on many systems, and rounds down to .1. Lame. */ - sprintf(temp, "%.*f", places, parse_number(args[0]) + 0.0000001); - - /* Handle the bizarre "-0" sprintf problem. */ - if (!strcmp(temp, "-0")) - safe_chr('0', buff, bp); +#ifdef HAVE_ROUND + if (places == 0) + rounded = round(n); else - safe_str(temp, buff, bp); + rounded = fround(n, places); +#else + rounded = fround(n, places); +#endif + + safe_number(rounded, buff, bp); } /* ARGSUSED */ @@ -1089,10 +1108,21 @@ FUNCTION(fun_ln) safe_number(log(num), buff, bp); } +#ifndef HAVE_LOG2 +static double +log2(double x) +{ + return log(x) / log(2.0); +} +#endif + /* ARGSUSED */ FUNCTION(fun_log) { - NVAL num, base; + NVAL num; + NVAL base = 10.0; + bool base_is_e = false; + if (!is_number(args[0])) { safe_str(T(e_nums), buff, bp); return; @@ -1111,16 +1141,25 @@ FUNCTION(fun_log) } if (nargs == 2) { if (!is_number(args[1])) { - safe_str(T(e_nums), buff, bp); - return; - } - base = parse_number(args[1]); + if (args[1][0] == 'e' && args[1][1] == '\0') { + base_is_e = true; + } else { + safe_str(T(e_nums), buff, bp); + return; + } + } else + base = parse_number(args[1]); - if (base <= 1) { + if (base_is_e) + safe_number(log(num), buff, bp); + else if (base <= 1) safe_str(T("#-1 BASE OUT OF RANGE"), buff, bp); - return; - } - safe_number(log(num) / log(base), buff, bp); + else if (base == 10) + safe_number(log10(num), buff, bp); + else if (base == 2) + safe_number(log2(num), buff, bp); + else + safe_number(log(num) / log(base), buff, bp); } else safe_number(log10(num), buff, bp); } @@ -1184,10 +1223,29 @@ FUNCTION(fun_root) root = sqrt(x); break; case 3: - /* TO-DO: Configure check for cbrt()? */ +#ifdef HAVE_CBRT + root = cbrt(x); + break; +#endif default: - /* Spiffy logarithm trick */ - root = exp(log(x) / n); + { + /* Root-finding algorithm detailed at + http://en.wikipedia.org/wiki/Nth_root_algorithm */ + NVAL lastx, inverse_n, nm1, epsilon; + int count = -1; + /* See http://en.wikipedia.org/wiki/Talk:Nth_root_algorithm for + initial guess equation, which is basically the old root-finding + equation using 2 instead of e as a base. */ + root = pow(2.0, ceil(ceil(log2(x)) / n)); + inverse_n = 1.0 / n; + nm1 = n - 1.0; + epsilon = pow(0.1, FLOAT_PRECISION + 1); + do { + count += 1; + lastx = root; + root = inverse_n * ((nm1 * root) + (x / pow(root, nm1))); + } while (fabs(lastx - root) > epsilon || count < 100); + } } if (sign) @@ -1264,7 +1322,7 @@ frac(double v, double *RESTRICT n, double *RESTRICT d, double error) do { m *= 10.0; } while (m * epsilon < 1.0); - epsilon = 1.0 / m * floor(0.5 + m * epsilon); + epsilon = 1.0 / m * (floor(0.5 + m * epsilon)); if (epsilon <= error) return epsilon; } while (!EQ(r, 0.0)); @@ -1396,12 +1454,12 @@ static void do_spellnum(char *num, unsigned int len, char **buff, char ***bp) { static const char *bigones[] = - { "", "thousand", "million", "billion", "trillion" }; + { "", "thousand", "million", "billion", "trillion" }; static const char *singles[] = { "", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine" }; static const char *special[] = - { "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", + { "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen" }; @@ -1460,7 +1518,7 @@ static void do_ordinalize(char **buff, char ***bp) { char *p; - int i, len; + size_t i, len; static const char *singles[] = { "one", "two", "three", "four", "five", "six", "seven", "eight", "nine" }; @@ -1474,7 +1532,7 @@ do_ordinalize(char **buff, char ***bp) if ((p >= *buff) && !strncasecmp(p, singles[i], len)) { **bp = p; safe_str(singleths[i], *buff, *bp); - return; /* done */ + return; /* done */ } } /* The string didn't end with a single. How about a y? */ @@ -1514,9 +1572,9 @@ FUNCTION(fun_spellnum) char num[BUFFER_LEN]; char *number, /* the whole number (without -/+ sign and leading zeros) */ *pnumber = args[0], *pnum1, *pnum2 = NULL; /* part 1 and 2 of the number respectively */ - unsigned int len, m, minus = 0, /* is the number negative? */ - dot = 0, len1, len2; /* length of part 1 and 2 respectively */ - int ordinal_mode; + bool minus = 0; /* is the number negative? */ + size_t len, m, dot = 0, len1, len2; /* length of part 1 and 2 respectively */ + bool ordinal_mode; ordinal_mode = (strcmp(called_as, "ORDINAL") == 0); pnumber = trim_space_sep(args[0], ' '); @@ -1543,9 +1601,9 @@ FUNCTION(fun_spellnum) if (*pnumber == '.') { if (ordinal_mode) { - /* Only integers may be ordinalized */ - safe_str(T(e_int), buff, bp); - return; + /* Only integers may be ordinalized */ + safe_str(T(e_int), buff, bp); + return; } if (dot) { safe_str(T(e_num), buff, bp); @@ -1650,12 +1708,12 @@ FUNCTION(fun_band) FUNCTION(fun_bnand) { - unsigned int retval; - if (!is_uinteger(args[0]) || !is_uinteger(args[1])) { + UIVAL retval; + if (!is_uival(args[0]) || !is_uival(args[1])) { safe_str(T(e_uints), buff, bp); return; } - retval = parse_uinteger(args[0]) & (~parse_uinteger(args[1])); + retval = parse_uival(args[0]) & (~parse_uival(args[1])); safe_uinteger(retval, buff, bp); } @@ -1671,11 +1729,11 @@ FUNCTION(fun_bxor) FUNCTION(fun_bnot) { - if (!is_uinteger(args[0])) { + if (!is_uival(args[0])) { safe_str(T(e_uint), buff, bp); return; } - safe_uinteger(~parse_uinteger(args[0]), buff, bp); + safe_uinteger(~parse_uival(args[0]), buff, bp); } /* ARGSUSED */ @@ -1708,33 +1766,45 @@ FUNCTION(fun_lmath) char **ptr; MATH *op; - /* Allocate memory */ - ptr = (char **) mush_malloc(sizeof(char *) * BUFFER_LEN, "string"); - if (!delim_check(buff, bp, nargs, args, 3, &sep)) { - mush_free((Malloc_t) ptr, "string"); return; } + /* Allocate memory */ + ptr = mush_calloc(BUFFER_LEN, sizeof(char *), "string"); + nptr = list2arr(ptr, BUFFER_LEN, args[1], sep); - op = math_hash_lookup(args[0]); + op = math_hash_lookup(args[0], arglens[0]); if (!op) { safe_str(T("#-1 UNKNOWN OPERATION"), buff, bp); - mush_free((Malloc_t) ptr, "string"); + mush_free(ptr, "string"); return; } op->func(ptr, nptr, buff, bp); - mush_free((Malloc_t) ptr, "string"); + mush_free(ptr, "string"); } +extern char from_base_64[256]; +extern char to_base_64[]; + +extern char from_base_36[256]; +extern char to_base_36[]; + FUNCTION(fun_baseconv) { long n; + int m; int from, to; - char *end; + char *ptr; + char numbuff[BUFFER_LEN], *nbp; + + + /* Base 36 by default */ + char *frombase = from_base_36; + char *tobase = to_base_36; if (!(is_integer(args[1]) && is_integer(args[2]))) { safe_str(T(e_ints), buff, bp); @@ -1744,24 +1814,58 @@ FUNCTION(fun_baseconv) from = parse_integer(args[1]); to = parse_integer(args[2]); - if (from < 2 || from > 36) { + if (from < 2 || from > 64) { safe_str(T("#-1 FROM BASE OUT OF RANGE"), buff, bp); return; } - if (to < 2 || to > 36) { + if (from > 36) { + frombase = from_base_64; + } + + if (to < 2 || to > 64) { safe_str(T("#-1 TO BASE OUT OF RANGE"), buff, bp); return; } - n = strtol(trim_space_sep(args[0], ' '), &end, from); + if (to > 36) { + tobase = to_base_64; + } + // Parse it. + ptr = trim_space_sep(args[0], ' '); + n = 0; + while (ptr && *ptr) { + n *= from; + if (frombase[(unsigned char) *ptr] >= 0) { + n += frombase[(unsigned char) *ptr]; + ptr++; + } else { + safe_str(T("#-1 MALFORMED NUMBER"), buff, bp); + return; + } + } - if (*end != '\0') { - safe_str(T("#-1 MALFORMED NUMBER"), buff, bp); + // Handle the 0-case. (And quickly handle < to_base case, too!) + if (n < to) { + safe_chr(tobase[(unsigned char) n], buff, bp); return; } - format_long(n, buff, bp, BUFFER_LEN, to); + nbp = numbuff; + + // This comes out backwards. + while (n > 0) { + m = n % to; + n = n / to; + safe_chr(tobase[(unsigned char) m], numbuff, &nbp); + } + + // Reverse back onto buff. + nbp--; + while (nbp >= numbuff) { + safe_chr(*nbp, buff, bp); + nbp--; + } } MATH_FUNC(math_add) @@ -1932,28 +2036,29 @@ MATH_FUNC(math_mean) MATH_FUNC(math_div) { /* Division, truncating to match remainder */ - int divresult, n; + IVAL divresult; + int n; if (nptr < 1) { safe_chr('0', buff, bp); return; } - if (!is_integer(ptr[0])) { + if (!is_ival(ptr[0])) { safe_str(T(e_ints), buff, bp); return; } - divresult = parse_integer(ptr[0]); + divresult = parse_ival(ptr[0]); for (n = 1; n < nptr; n++) { - int temp; - if (!is_integer(ptr[n])) { + IVAL temp; + if (!is_ival(ptr[n])) { safe_str(T(e_ints), buff, bp); return; } - temp = parse_integer(ptr[n]); + temp = parse_ival(ptr[n]); - if (EQ(temp, 0)) { + if (temp == 0) { safe_str(T("#-1 DIVISION BY ZERO"), buff, bp); return; } @@ -1976,26 +2081,27 @@ MATH_FUNC(math_div) MATH_FUNC(math_floordiv) { /* Division taking the floor, to match modulo */ - int divresult, n; + IVAL divresult; + int n; if (nptr < 1) { safe_chr('0', buff, bp); return; } - if (!is_integer(ptr[0])) { + if (!is_ival(ptr[0])) { safe_str(T(e_ints), buff, bp); return; } - divresult = parse_integer(ptr[0]); + divresult = parse_ival(ptr[0]); for (n = 1; n < nptr; n++) { - int temp; - if (!is_integer(ptr[n])) { + IVAL temp; + if (!is_ival(ptr[n])) { safe_str(T(e_ints), buff, bp); return; } - temp = parse_integer(ptr[n]); + temp = parse_ival(ptr[n]); if (temp == 0) { safe_str(T("#-1 DIVISION BY ZERO"), buff, bp); @@ -2042,7 +2148,7 @@ MATH_FUNC(math_fdiv) } temp = parse_number(ptr[n]); - if (temp == 0) { + if (EQ(temp, 0)) { safe_str(T("#-1 DIVISION BY ZERO"), buff, bp); return; } @@ -2055,26 +2161,27 @@ MATH_FUNC(math_fdiv) MATH_FUNC(math_modulo) { /* Modulo */ - int divresult, n; + IVAL divresult; + int n; if (nptr < 1) { safe_chr('0', buff, bp); return; } - if (!is_integer(ptr[0])) { + if (!is_ival(ptr[0])) { safe_str(T(e_ints), buff, bp); return; } - divresult = parse_integer(ptr[0]); + divresult = parse_ival(ptr[0]); for (n = 1; n < nptr; n++) { - int temp; - if (!is_integer(ptr[n])) { + IVAL temp; + if (!is_ival(ptr[n])) { safe_str(T(e_ints), buff, bp); return; } - temp = parse_integer(ptr[n]); + temp = parse_ival(ptr[n]); if (temp == 0) { safe_str(T("#-1 DIVISION BY ZERO"), buff, bp); @@ -2099,26 +2206,27 @@ MATH_FUNC(math_modulo) MATH_FUNC(math_remainder) { /* Remainder */ - int divresult, n; + IVAL divresult; + int n; if (nptr < 1) { safe_chr('0', buff, bp); return; } - if (!is_integer(ptr[0])) { + if (!is_ival(ptr[0])) { safe_str(T(e_ints), buff, bp); return; } - divresult = parse_integer(ptr[0]); + divresult = parse_ival(ptr[0]); for (n = 1; n < nptr; n++) { - int temp; - if (!is_integer(ptr[n])) { + IVAL temp; + if (!is_ival(ptr[n])) { safe_str(T(e_ints), buff, bp); return; } - temp = parse_integer(ptr[n]); + temp = parse_ival(ptr[n]); if (temp == 0) { safe_str(T("#-1 DIVISION BY ZERO"), buff, bp); @@ -2142,7 +2250,7 @@ MATH_FUNC(math_remainder) MATH_FUNC(math_band) { - unsigned int bretval; + UIVAL bretval; int n; if (nptr < 1) { @@ -2150,26 +2258,26 @@ MATH_FUNC(math_band) return; } - if (!is_uinteger(ptr[0])) { + if (!is_uival(ptr[0])) { safe_str(T(e_uints), buff, bp); return; } - bretval = parse_uinteger(ptr[0]); + bretval = parse_uival(ptr[0]); for (n = 1; n < nptr; n++) { - if (!is_uinteger(ptr[n])) { + if (!is_uival(ptr[n])) { safe_str(T(e_uints), buff, bp); return; } - bretval &= parse_uinteger(ptr[n]); + bretval &= parse_uival(ptr[n]); } safe_uinteger(bretval, buff, bp); } MATH_FUNC(math_bor) { - unsigned int bretval; + UIVAL bretval; int n; if (nptr < 1) { @@ -2177,26 +2285,26 @@ MATH_FUNC(math_bor) return; } - if (!is_uinteger(ptr[0])) { + if (!is_uival(ptr[0])) { safe_str(T(e_uints), buff, bp); return; } - bretval = parse_uinteger(ptr[0]); + bretval = parse_uival(ptr[0]); for (n = 1; n < nptr; n++) { - if (!is_uinteger(ptr[n])) { + if (!is_uival(ptr[n])) { safe_str(T(e_uints), buff, bp); return; } - bretval |= parse_uinteger(ptr[n]); + bretval |= parse_uival(ptr[n]); } safe_uinteger(bretval, buff, bp); } MATH_FUNC(math_bxor) { - unsigned int bretval; + UIVAL bretval; int n; if (nptr < 1) { @@ -2204,19 +2312,19 @@ MATH_FUNC(math_bxor) return; } - if (!is_uinteger(ptr[0])) { + if (!is_uival(ptr[0])) { safe_str(T(e_uints), buff, bp); return; } - bretval = parse_uinteger(ptr[0]); + bretval = parse_uival(ptr[0]); for (n = 1; n < nptr; n++) { - if (!is_uinteger(ptr[n])) { + if (!is_uival(ptr[n])) { safe_str(T(e_uints), buff, bp); return; } - bretval ^= parse_uinteger(ptr[n]); + bretval ^= parse_uival(ptr[n]); } safe_uinteger(bretval, buff, bp); } @@ -2282,25 +2390,16 @@ MATH_FUNC(math_xor) } -static int -nval_sort(const void *a, const void *b) -{ - const NVAL *x = a, *y = b; - const double epsilon = pow(10, -FLOAT_PRECISION); - int eq = (fabs(*x - *y) <= (epsilon * fabs(*x))); - return eq ? 0 : (*x > *y ? 1 : -1); -} - static NVAL -find_median(NVAL * numbers, int nargs) +find_median(NVAL *numbers, int nargs) { if (nargs == 0) return 0; if (nargs == 1) return numbers[0]; - qsort(numbers, nargs, sizeof(NVAL), nval_sort); + qsort(numbers, nargs, sizeof(NVAL), nval_comp); if ((nargs % 2) == 1) /* Odd # of items */ return numbers[nargs / 2]; @@ -2376,79 +2475,60 @@ MATH_FUNC(math_stddev) safe_number(sqrt(s / (nptr - 1)), buff, bp); } -/** A list of MATH_FUNCs that are suitable for lmath() */ -MATH mlist[] = { - {"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} - , - {NULL, NULL} -}; - -static MATH * -math_hash_lookup(char *name) -{ - return (MATH *) hashfind(strupper(name), &htab_math); -} +MATH_FUNC(math_dist2d) +{ + NVAL d1, d2, r; + if (nptr != 4) { + safe_str(T("#-1 FUNCTION (dist2d) EXPECTS 4 ARGUMENTS"), buff, bp); + return; + } -static void -math_hash_insert(const char *name, MATH * func) -{ - hashadd(name, (void *) func, &htab_math); + if (!is_number(ptr[0]) || !is_number(ptr[1]) || + !is_number(ptr[2]) || !is_number(ptr[3])) { + safe_str(T(e_nums), buff, bp); + return; + } + d1 = parse_number(ptr[0]) - parse_number(ptr[2]); + d2 = parse_number(ptr[1]) - parse_number(ptr[3]); + r = d1 * d1 + d2 * d2; +#ifndef HAS_IEEE_MATH + /* You can overflow, which is bad. */ + if (r < 0) { + safe_str(T("#-1 OVERFLOW ERROR"), buff, bp); + return; + } +#endif + safe_number(sqrt(r), buff, bp); } -/** Initialize the math function hash table. */ -void -init_math_hashtab(void) +MATH_FUNC(math_dist3d) { - MATH *fp; + NVAL d1, d2, d3, r; - hashinit(&htab_math, 32, sizeof(MATH)); - for (fp = mlist; fp->name; fp++) - math_hash_insert(fp->name, (MATH *) fp); + if (nptr != 6) { + safe_str(T("#-1 FUNCTION (dist3d) expects 6 arguments"), buff, bp); + return; + } + + if (!is_number(ptr[0]) || !is_number(ptr[1]) || + !is_number(ptr[2]) || !is_number(ptr[3]) || + !is_number(ptr[4]) || !is_number(ptr[5])) { + safe_str(T(e_nums), buff, bp); + return; + } + d1 = parse_number(ptr[0]) - parse_number(ptr[3]); + d2 = parse_number(ptr[1]) - parse_number(ptr[4]); + d3 = parse_number(ptr[2]) - parse_number(ptr[5]); + r = d1 * d1 + d2 * d2 + d3 * d3; +#ifndef HAS_IEEE_MATH + /* You can overflow, which is bad. */ + if (r < 0) { + safe_str(T("#-1 OVERFLOW ERROR"), buff, bp); + return; + } +#endif + safe_number(sqrt(r), buff, bp); } static NVAL @@ -2491,6 +2571,36 @@ rad_to_angle(NVAL angle, const char *to) } } +/* ARGSUSED */ +FUNCTION(fun_romantoarabic) { + int arabic; + + arabic = RomanToArabic(args[0]); + + if(arabic != -1) + safe_number(arabic, buff, bp); + else + safe_str(T(e_range), buff, bp); +} + +/* ARGSUSED */ +FUNCTION(fun_arabictoroman) { + char *roman_num; + + if (!is_number(args[0])) { + safe_str(T(e_num), buff, bp); + return; + } + + roman_num = ArabicToRoman(parse_integer(args[0])); + + if(roman_num == NULL) + safe_str(T(e_range), buff, bp); + else + safe_str(roman_num, buff, bp); + +} + /* Take a normal number & make it roman */ #define ROMAN_CDOWN(num,rstr) while((i - num) >= 0) { \ safe_format(roman, &roman_bp, "%s", rstr ); \ diff --git a/src/funmisc.c b/src/funmisc.c index 98f2543..9664663 100644 --- a/src/funmisc.c +++ b/src/funmisc.c @@ -29,6 +29,7 @@ #include "game.h" #include "attrib.h" #include "confmagic.h" +#include "ansi.h" #ifdef WIN32 #pragma warning( disable : 4761) /* NJG: disable warning re conversion */ @@ -83,6 +84,17 @@ FUNCTION(fun_pemit) orator = saved_orator; } +FUNCTION(fun_message) +{ + int i; + char *argv[10]; + + for (i = 0; (i + 3) < nargs; i++) { + argv[i] = args[i + 3]; + } + + do_message_list(executor, executor, args[0], args[2], args[1], 0, i, argv); +} /* ARGSUSED */ FUNCTION(fun_oemit) @@ -189,6 +201,87 @@ FUNCTION(fun_setq) } } +FUNCTION(fun_letq) +{ + char **values = NULL; + int *regs = NULL; + int npairs; + int n; + char tbuf[BUFFER_LEN], *tbp; + char *preserve[NUMQ]; + const char *p; + + if ((nargs % 2) != 1) { + safe_str(T("#-1 FUNCTION (letq) EXPECTS AN ODD NUMBER OF ARGUMENTS"), + buff, bp); + return; + } + + npairs = (nargs - 1) / 2; + + for (n = 0; n < NUMQ; n++) + preserve[n] = NULL; + + if (npairs) { + values = mush_calloc(npairs, sizeof(char *), "letq.values"); + if (!values) { + safe_str(T("#-1 UNABLE TO ALLOCATE MEMORY"), buff, bp); + return; + } + + regs = mush_calloc(npairs, sizeof(int), "letq.registers"); + if (!regs) { + safe_str(T("#-1 UNABLE TO ALLOCATE MEMORY"), buff, bp); + mush_free(values, "letq.values"); + return; + } + + for (n = 0; n < npairs; n++) { + int i = n * 2; + + tbp = tbuf; + p = args[i]; + process_expression(tbuf, &tbp, &p, executor, caller, enactor, PE_DEFAULT, + PT_DEFAULT, pe_info); + *tbp = '\0'; + regs[n] = qreg_indexes[(unsigned char) tbuf[0]]; + if (regs[n] < 0) { + safe_str(T("#-1 REGISTER OUT OF RANGE"), buff, bp); + goto cleanup; + } + + tbp = tbuf; + p = args[i + 1]; + process_expression(tbuf, &tbp, &p, executor, caller, enactor, PE_DEFAULT, + PT_DEFAULT, pe_info); + *tbp = '\0'; + values[n] = mush_strdup(tbuf, "letq.value"); + if (!values[n]) { + safe_str(T("#-1 UNABLE TO ALLOCATE MEMORY"), buff, bp); + goto cleanup; + } + } + + for (n = 0; n < npairs; n++) { + save_partial_global_reg("letq", preserve, regs[n]); + mush_strncpy(global_eval_context.renv[regs[n]], values[n], BUFFER_LEN); + } + } + p = args[nargs - 1]; + process_expression(buff, bp, &p, executor, caller, enactor, PE_DEFAULT, + PT_DEFAULT, pe_info); + +cleanup: + if (regs) + mush_free(regs, "letq.registers"); + if (values) { + restore_partial_global_regs("letq", preserve); + for (n = 0; n < npairs; n++) + mush_free(values[n], "letq.value"); + mush_free(values, "letq.values"); + } +} + /* ARGSUSED */ FUNCTION(fun_r) { @@ -420,18 +513,37 @@ FUNCTION(fun_if) { char tbuf[BUFFER_LEN], *tp; char const *sp; + /* Since this may be used as COND(), NCOND(), CONDALL() or NCONDALL, + * we check for that. */ + int findtrue = 1; + int findall = 0; + int found = 0; + int i; - tp = tbuf; - sp = args[0]; - process_expression(tbuf, &tp, &sp, executor, caller, enactor, - PE_DEFAULT, PT_DEFAULT, pe_info); - *tp = '\0'; - if (parse_boolean(tbuf)) { - sp = args[1]; - process_expression(buff, bp, &sp, executor, caller, enactor, + if (called_as[0] == 'N') + findtrue = 0; + + if (strstr(called_as, "ALL")) + findall = 1; + + for (i = 0; i < nargs - 1; i += 2) { + tp = tbuf; + sp = args[i]; + process_expression(tbuf, &tp, &sp, executor, caller, enactor, PE_DEFAULT, PT_DEFAULT, pe_info); - } else if (nargs > 2) { - sp = args[2]; + *tp = '\0'; + if (parse_boolean(tbuf) == findtrue) { + sp = args[i + 1]; + process_expression(buff, bp, &sp, executor, caller, enactor, + PE_DEFAULT, PT_DEFAULT, pe_info); + if (!findall) + return; + found = 1; + } + } + /* If we've found no true case, run the default if it exists. */ + if (!found && (nargs & 1)) { + sp = args[nargs - 1]; process_expression(buff, bp, &sp, executor, caller, enactor, PE_DEFAULT, PT_DEFAULT, pe_info); } @@ -499,7 +611,7 @@ soundex(str) p++; /* Convert letters to soundex values, squash duplicates */ while (*q) { - if (!isalpha((unsigned char) *q) || !isascii((unsigned char) *q)) { + if (!isalpha((unsigned char) *q) || (unsigned char) *q > 127) { q++; continue; } @@ -571,7 +683,7 @@ FUNCTION(fun_soundlike) /* ARGSUSED */ FUNCTION(fun_functions) { - safe_str(list_functions(), buff, bp); + safe_str(list_functions(nargs == 1 ? args[0] : NULL), buff, bp); } /* ARGSUSED */ @@ -598,7 +710,9 @@ FUNCTION(fun_list) else if (string_prefix("fullmotd", args[0]) && Admin(executor)) safe_str(cf_fullmotd_msg, buff, bp); else if (string_prefix("functions", args[0])) - safe_str(list_functions(), buff, bp); + safe_str(list_functions(NULL), buff, bp); + else if (string_prefix("@functions", args[0])) + safe_str(list_functions("local"), buff, bp); else if (string_prefix("commands", args[0])) safe_str(list_commands(), buff, bp); else if (string_prefix("attribs", args[0])) @@ -648,7 +762,7 @@ FUNCTION(fun_scan) enum whichof_t { DO_FIRSTOF, DO_ALLOF }; static void do_whichof(char *args[], int nargs, enum whichof_t flag, char *buff, char **bp, - dbref executor, dbref caller, dbref enactor, PE_Info * pe_info) + dbref executor, dbref caller, dbref enactor, PE_Info *pe_info) { int j; char tbuf[BUFFER_LEN], *tp; diff --git a/src/funstr.c b/src/funstr.c index 3b11cf0..f80574f 100644 --- a/src/funstr.c +++ b/src/funstr.c @@ -12,9 +12,10 @@ #include #include #include +#include #include "conf.h" -#include "ansi.h" #include "externs.h" +#include "ansi.h" #include "case.h" #include "match.h" #include "parse.h" @@ -25,6 +26,7 @@ #include "mushdb.h" #include "htab.h" #include "lock.h" +#include "sort.h" #include "confmagic.h" @@ -32,19 +34,18 @@ #pragma warning( disable : 4761) /* NJG: disable warning re conversion */ #endif -HASHTAB htab_tag; /**< Hash table of safe html tags */ - #define MAX_COLS 32 /**< Maximum number of columns for align() */ -static int wraplen(char *str, int maxlen); +static int wraplen(char *str, size_t maxlen); static int align_one_line(char *buff, char **bp, int ncols, int cols[MAX_COLS], int calign[MAX_COLS], char *ptrs[MAX_COLS], ansi_string *as[MAX_COLS], int linenum, char *fieldsep, int fslen, char *linesep, int lslen, char filler); static int comp_gencomp(dbref exceutor, char *left, char *right, char *type); -void init_tag_hashtab(void); void init_pronouns(void); +extern signed char qreg_indexes[UCHAR_MAX + 1]; + /** Return an indicator of a player's gender. * \param player player whose gender is to be checked. * \retval 0 neuter. @@ -353,10 +354,10 @@ FUNCTION(fun_right) } as = parse_ansi_string(args[0]); - if ((size_t) len > as->len) + if (len > as->len) safe_strl(args[0], arglens[0], buff, bp); else - safe_ansi_string(as, as->len - len, as->len, buff, bp); + safe_ansi_string(as, as->len - len, len, buff, bp); free_ansi_string(as); } @@ -364,7 +365,7 @@ FUNCTION(fun_right) FUNCTION(fun_strinsert) { /* Insert a string into another */ - ansi_string *as; + ansi_string *dst, *src; int pos; if (!is_integer(args[1])) { @@ -378,21 +379,22 @@ FUNCTION(fun_strinsert) return; } - as = parse_ansi_string(args[0]); - - if ((size_t) pos > as->len) { - /* Fast special case - concatenate args[2] to args[0] */ + dst = parse_ansi_string(args[0]); + if (pos > dst->len) { safe_strl(args[0], arglens[0], buff, bp); safe_strl(args[2], arglens[0], buff, bp); - free_ansi_string(as); + free_ansi_string(dst); return; } - safe_ansi_string(as, 0, pos, buff, bp); - safe_strl(args[2], arglens[2], buff, bp); - safe_ansi_string(as, pos, as->len, buff, bp); - free_ansi_string(as); + src = parse_ansi_string(args[2]); + ansi_string_insert(dst, pos, src); + + safe_ansi_string(dst, 0, dst->len, buff, bp); + + free_ansi_string(dst); + free_ansi_string(src); } /* ARGSUSED */ @@ -416,7 +418,7 @@ FUNCTION(fun_delete) as = parse_ansi_string(args[0]); - if ((size_t) pos > as->len || num == 0) { + if (pos > as->len || num == 0) { safe_strl(args[0], arglens[0], buff, bp); free_ansi_string(as); return; @@ -438,10 +440,10 @@ FUNCTION(fun_delete) /* ARGSUSED */ FUNCTION(fun_strreplace) { - ansi_string *as, *anew; - int start, len, end; + ansi_string *dst, *src; + int start, len; - if (!is_integer(args[1]) || !is_integer(args[2])) { + if (!is_integer(args[1]) || !is_integer(args[2])) { safe_str(T(e_ints), buff, bp); return; } @@ -454,20 +456,14 @@ FUNCTION(fun_strreplace) return; } - as = parse_ansi_string(args[0]); - anew = parse_ansi_string(args[3]); - - safe_ansi_string(as, 0, start, buff, bp); - safe_ansi_string(anew, 0, anew->len, buff, bp); + dst = parse_ansi_string(args[0]); + src = parse_ansi_string(args[3]); - end = start + len; - - if ((size_t) end < as->len) - safe_ansi_string(as, end, as->len - end, buff, bp); - - free_ansi_string(as); - free_ansi_string(anew); + ansi_string_replace(dst, start, len, src); + safe_ansi_string(dst, 0, dst->len, buff, bp); + free_ansi_string(dst); + free_ansi_string(src); } static int @@ -575,7 +571,7 @@ FUNCTION(fun_lpos) int first = 1; if (args[1][0]) - c = args[1][0]; + c = remove_markup(args[1], &len)[0]; pos = remove_markup(args[0], &len); for (n = 0; n < len; n++) @@ -593,13 +589,39 @@ FUNCTION(fun_lpos) FUNCTION(fun_strmatch) { char tbuf[BUFFER_LEN]; + char *ret[36]; char *t; size_t len; + int matches; + int i; + char *qregs[NUMQ]; + int nqregs; + int qindex; + char match_space[BUFFER_LEN * 2]; + ssize_t match_space_len = BUFFER_LEN * 2; + /* matches a wildcard pattern for an _entire_ string */ t = remove_markup(args[0], &len); memcpy(tbuf, t, len); - safe_boolean(quick_wild(remove_markup(args[1], NULL), tbuf), buff, bp); + memset(ret, 0, 36); + matches = wild_match_case_r(remove_markup(args[1], NULL), tbuf, 0, ret, + NUMQ, match_space, match_space_len); + safe_boolean(matches, buff, bp); + + if (nargs > 2) { + /* Now, assign the captures if desired */ + nqregs = list2arr(qregs, NUMQ, args[2], ' '); + + for (i = 0; i < nqregs; i++) { + if (ret[i] && qregs[i][0] && !qregs[i][1]) { + qindex = qreg_indexes[(unsigned char) qregs[i][0]]; + if (qindex >= 0 && global_eval_context.renv[qindex]) { + strcpy(global_eval_context.renv[qindex], ret[i]); + } + } + } + } } /* ARGSUSED */ @@ -629,14 +651,11 @@ FUNCTION(fun_merge) * char in s2. */ - char *str, *rep; + int i, j; + size_t len; + char *ptr = args[0]; char matched[UCHAR_MAX + 1]; - - /* do length checks first */ - if (arglens[0] != arglens[1]) { - safe_str(T("#-1 STRING LENGTHS MUST BE EQUAL"), buff, bp); - return; - } + ansi_string *as; memset(matched, 0, sizeof matched); @@ -645,15 +664,70 @@ FUNCTION(fun_merge) matched[(unsigned char) ' '] = 1; else { unsigned char *p; - for (p = (unsigned char *) args[2]; p && *p; p++) + for (p = (unsigned char *) remove_markup(args[2], &len); p && *p; p++) matched[*p] = 1; } + as = parse_ansi_string(args[1]); + + /* do length checks first */ + if (as->len != ansi_strlen(ptr)) { + safe_str(T("#-1 STRING LENGTHS MUST BE EQUAL"), buff, bp); + free_ansi_string(as); + return; + } + /* walk strings, copy from the appropriate string */ - for (str = args[0], rep = args[1]; *str && *rep; str++, rep++) { - *str = matched[(unsigned char) *str] ? *rep : *str; + i = 0; + ptr = args[0]; + while (*ptr) { + switch (*ptr) { + case ESC_CHAR: + while (*ptr && *ptr != 'm') { + safe_chr(*(ptr++), buff, bp); + } + safe_chr(*(ptr++), buff, bp); + break; + case TAG_START: + while (*ptr && *ptr != TAG_END) { + safe_chr(*(ptr++), buff, bp); + } + safe_chr(*(ptr++), buff, bp); + break; + default: + if (matched[(unsigned char) *ptr]) { + j = 0; + while (*ptr && matched[(unsigned char) *ptr]) { + ptr++; + j++; + switch (*ptr) { + case ESC_CHAR: + safe_ansi_string(as, i, j, buff, bp); + i += j; + j = 0; + while (*ptr && *ptr != 'm') + safe_chr(*(ptr++), buff, bp); + break; + case TAG_START: + safe_ansi_string(as, i, j, buff, bp); + i += j; + j = 0; + while (*ptr && *ptr != TAG_END) + safe_chr(*(ptr++), buff, bp); + break; + } + } + if (j != 0) { + safe_ansi_string(as, i, j, buff, bp); + i += j; + } + } else { + i++; + safe_chr(*(ptr++), buff, bp); + } + } } - safe_str(args[0], buff, bp); + free_ansi_string(as); } /* ARGSUSED */ @@ -699,17 +773,17 @@ FUNCTION(fun_tr) if (dest > cur) { for (; cur <= dest; cur++) { if (goodchr(cur)) - safe_chr(cur, instr, &ip); + safe_chr((char) cur, instr, &ip); } } else { for (; cur >= dest; cur--) { if (goodchr(cur)) - safe_chr(cur, instr, &ip); + safe_chr((char) cur, instr, &ip); } } c += 3; } else { - safe_chr(cur, instr, &ip); + safe_chr((char) cur, instr, &ip); c++; } } @@ -737,17 +811,17 @@ FUNCTION(fun_tr) if (dest > cur) { for (; cur <= dest; cur++) { if (goodchr(cur)) - safe_chr(cur, outstr, &op); + safe_chr((char) cur, outstr, &op); } } else { for (; cur >= dest; cur--) { if (goodchr(cur)) - safe_chr(cur, outstr, &op); + safe_chr((char) cur, outstr, &op); } } c += 3; } else { - safe_chr(cur, outstr, &op); + safe_chr((char) cur, outstr, &op); c++; } } @@ -766,7 +840,6 @@ FUNCTION(fun_tr) /* walk the string, translating characters */ as = parse_ansi_string(args[0]); - populate_codes(as); len = as->len; for (i = 0; i < len; i++) { as->text[i] = charmap[(unsigned char) as->text[i]]; @@ -862,25 +935,18 @@ FUNCTION(fun_repeat) /* ARGSUSED */ FUNCTION(fun_scramble) { - int n, i, j; - ansi_string *as; + ansi_string *as, *dst; if (!*args[0]) return; as = parse_ansi_string(args[0]); - populate_codes(as); - n = as->len; - for (i = 0; i < n; i++) { - char t, *tcode; - j = get_random_long(i, n - 1); - t = as->text[j]; - as->text[j] = as->text[i]; - as->text[i] = t; - tcode = as->codes[j]; - as->codes[j] = as->codes[i]; - as->codes[i] = tcode; + dst = scramble_ansi_string(as); + if (dst) { + free_ansi_string(as); + as = dst; } + safe_ansi_string(as, 0, as->len, buff, bp); free_ansi_string(as); } @@ -891,7 +957,9 @@ FUNCTION(fun_ljust) /* pads a string with trailing blanks (or other fill character) */ size_t spaces, len; - char sep; + ansi_string *as; + int fillq, fillr, i; + char fillstr[BUFFER_LEN], *fp; if (!is_uinteger(args[1])) { safe_str(T(e_uint), buff, bp); @@ -908,11 +976,29 @@ FUNCTION(fun_ljust) } spaces -= len; - if (!delim_check(buff, bp, nargs, args, 3, &sep)) + if (!args[2] || !*args[2]) { + /* Fill with spaces */ + safe_strl(args[0], arglens[0], buff, bp); + safe_fill(' ', spaces, buff, bp); return; - + } + len = ansi_strlen(args[2]); + if (!len) { + safe_str(T("#-1 FILL ARGUMENT MAY NOT BE ZERO-LENGTH"), buff, bp); + return; + } safe_strl(args[0], arglens[0], buff, bp); - safe_fill(sep, spaces, buff, bp); + as = parse_ansi_string(args[2]); + fillq = spaces / len; + fillr = spaces % len; + fp = fillstr; + for (i = 0; i < fillq; i++) + safe_ansi_string(as, 0, as->len, fillstr, &fp); + safe_ansi_string(as, 0, fillr, fillstr, &fp); + *fp = '\0'; + free_ansi_string(as); + safe_str(fillstr, buff, bp); + } /* ARGSUSED */ @@ -921,7 +1007,10 @@ FUNCTION(fun_rjust) /* pads a string with leading blanks (or other fill character) */ size_t spaces, len; - char sep; + ansi_string *as; + int fillq, fillr, i; + char fillstr[BUFFER_LEN], *fp; + if (!is_uinteger(args[1])) { safe_str(T(e_uint), buff, bp); @@ -938,11 +1027,29 @@ FUNCTION(fun_rjust) } spaces -= len; - if (!delim_check(buff, bp, nargs, args, 3, &sep)) + if (!args[2] || !*args[2]) { + /* Fill with spaces */ + safe_fill(' ', spaces, buff, bp); + safe_strl(args[0], arglens[0], buff, bp); return; - - safe_fill(sep, spaces, buff, bp); + } + len = ansi_strlen(args[2]); + if (!len) { + safe_str(T("#-1 FILL ARGUMENT MAY NOT BE ZERO-LENGTH"), buff, bp); + return; + } + as = parse_ansi_string(args[2]); + fillq = spaces / len; + fillr = spaces % len; + fp = fillstr; + for (i = 0; i < fillq; i++) + safe_ansi_string(as, 0, as->len, fillstr, &fp); + safe_ansi_string(as, 0, fillr, fillstr, &fp); + *fp = '\0'; + free_ansi_string(as); + safe_str(fillstr, buff, bp); safe_strl(args[0], arglens[0], buff, bp); + } /* ARGSUSED */ @@ -1045,7 +1152,8 @@ FUNCTION(fun_foreach) dbref thing; ATTR *attrib; - char const *ap, *lp; + const char *ap; + char *lp; char *asave, cbuf[2]; char *tptr[2]; char place[SBUF_LEN]; @@ -1141,7 +1249,7 @@ FUNCTION(fun_decompose) /* This function simply returns a decompose'd version of * the included string, such that * s(decompose(str)) == str, down to the last space, tab, - * and newline. Except for ansi. */ + * and newline. */ safe_str(decompose_str(args[0]), buff, bp); } @@ -1171,7 +1279,7 @@ FUNCTION(fun_escape) for (s = (unsigned char *) args[0]; *s; s++) { if ((s != (unsigned char *) args[0]) && escaped_chars[*s]) safe_chr('\\', buff, bp); - safe_chr(*s, buff, bp); + safe_chr((char) *s, buff, bp); } } } @@ -1183,9 +1291,11 @@ FUNCTION(fun_trim) * takes a delimiter argument and trim style. */ - char *p, *q, sep; - int trim; + char sep; + enum trim_style { TRIM_LEFT, TRIM_RIGHT, TRIM_BOTH } trim; int trim_style_arg, trim_char_arg; + ansi_string *as; + int i; /* Alas, PennMUSH and TinyMUSH used different orders for the arguments. * We'll give the users an option about it @@ -1209,19 +1319,21 @@ FUNCTION(fun_trim) /* If a trim style is provided, it must be the third argument. */ if (nargs >= trim_style_arg) { - switch (DOWNCASE(*args[trim_style_arg - 1])) { + switch (*args[trim_style_arg - 1]) { case 'l': - trim = 1; + case 'L': + trim = TRIM_LEFT; break; case 'r': - trim = 2; + case 'R': + trim = TRIM_RIGHT; break; default: - trim = 3; + trim = TRIM_BOTH; break; } } else - trim = 3; + trim = TRIM_BOTH; /* We will never need to check for buffer length overrunning, since * we will always get a smaller string. Thus, we can copy at the @@ -1229,19 +1341,24 @@ FUNCTION(fun_trim) */ /* If necessary, skip over the leading stuff. */ - p = args[0]; - if (trim != 2) { - while (*p == sep) - p++; + as = parse_ansi_string(args[0]); + if (trim != TRIM_RIGHT) { + for (i = 0; i < as->len; i++) { + if (as->text[i] != sep) + break; + as->text[i] = '\0'; + } } /* Cut off the trailing stuff, if appropriate. */ - if ((trim != 1) && (*p != '\0')) { - q = args[0] + arglens[0] - 1; - while ((q > p) && (*q == sep)) - q--; - q[1] = '\0'; + if ((trim != TRIM_LEFT)) { + for (i = as->len - 1; i >= 0; i--) { + if (as->text[i] != sep) + break; + as->text[i] = '\0'; + } } - safe_str(p, buff, bp); + safe_ansi_string(as, 0, as->len, buff, bp); + free_ansi_string(as); } /* ARGSUSED */ @@ -1261,32 +1378,38 @@ FUNCTION(fun_squish) * never going to end up with a longer string. */ - char *tp; + int i; char sep; + int insep = 1; + ansi_string *as; /* Figure out the character to squish */ if (!delim_check(buff, bp, nargs, args, 2, &sep)) return; + as = parse_ansi_string(args[0]); + /* get rid of trailing spaces first, so we don't have to worry about * them later. */ - tp = args[0] + arglens[0] - 1; - while ((tp > args[0]) && (*tp == sep)) - tp--; - tp[1] = '\0'; - - for (tp = args[0]; *tp == sep; tp++) /* skip leading spaces */ - ; - - while (*tp) { - safe_chr(*tp, buff, bp); - if (*tp == sep) - while (*tp == sep) - tp++; + for (i = as->len - 1; i >= 0; i--) { + if (as->text[i] == sep) + as->text[i] = '\0'; else - tp++; + break; } + /* Now trim leading and sequences */ + for (i = 0; i < as->len; i++) { + if (as->text[i] == sep) { + if (insep) + as->text[i] = '\0'; + insep = 1; + } else { + insep = 0; + } + } + safe_ansi_string(as, 0, as->len, buff, bp); + free_ansi_string(as); } /* ARGSUSED */ @@ -1329,37 +1452,6 @@ FUNCTION(fun_beep) safe_fill(BEEP_CHAR, k, buff, bp); } -/** Initialize the html tag hash table with all the safe tags from HTML 4.0 */ -void -init_tag_hashtab(void) -{ - static char dummy = 1; - int i = 0; - char tbuf[32]; - char *tbp; - static const char *safetags[] = { "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", - NULL - }; - hashinit(&htab_tag, 64, 1); - - while(safetags[i]) { - memset(tbuf, '\0', 32); - tbp = tbuf; - hashadd(safetags[i], (void *) &dummy, &htab_tag); - safe_format( tbuf, &tbp, "/%s", safetags[i] ); - hashadd(tbuf, (void *) &dummy, &htab_tag); - i++; - } -} - FUNCTION(fun_ord) { char *m; @@ -1375,7 +1467,7 @@ FUNCTION(fun_ord) if (len != 2) /* len includes trailing nul */ safe_str(T("#-1 FUNCTION (ORD) EXPECTS ONE CHARACTER"), buff, bp); else if(isprint(what) || what == '\n') - safe_integer((unsigned char) *m, buff, bp); + safe_integer(what, buff, bp); else safe_str(T("#-1 UNPRINTABLE CHARACTER"), buff, bp); } @@ -1418,336 +1510,45 @@ FUNCTION(fun_stripaccents) } } -/* ARGSUSED */ -FUNCTION(fun_html) -{ - if (!Site(executor)) - safe_str(T(e_perm), buff, bp); - else - safe_tag(args[0], buff, bp); -} - -/* ARGSUSED */ -FUNCTION(fun_tag) -{ - int i; - if (!Site(executor) && !hash_find(&htab_tag, strupper(args[0]))) - safe_str("#-1", buff, bp); - else { - safe_chr(TAG_START, buff, bp); - safe_strl(args[0], arglens[0], buff, bp); - for (i = 1; i < nargs; i++) { - if (ok_tag_attribute(executor, args[i])) { - safe_chr(' ', buff, bp); - safe_strl(args[i], arglens[i], buff, bp); - } - } - safe_chr(TAG_END, buff, bp); - } -} - -/* ARGSUSED */ -FUNCTION(fun_endtag) -{ - if (!Site(executor) && !hash_find(&htab_tag, strupper(args[0]))) - safe_str("#-1", buff, bp); - else - safe_tag_cancel(args[0], buff, bp); -} - -/* ARGSUSED */ -FUNCTION(fun_tagwrap) -{ - if (!Site(executor) && !hash_find(&htab_tag, strupper(args[0]))) - safe_str("#-1", buff, bp); - else { - if (nargs == 2) - safe_tag_wrap(args[0], NULL, args[1], buff, bp, executor); - else - safe_tag_wrap(args[0], args[1], args[2], buff, bp, executor); - } -} - -#define COL_FLASH (1) /**< ANSI flash attribute bit */ -#define COL_HILITE (2) /**< ANSI hilite attribute bit */ -#define COL_INVERT (4) /**< ANSI inverse attribute bit */ -#define COL_UNDERSCORE (8) /**< ANSI underscore attribute bit */ - -#define VAL_FLASH (5) /**< ANSI flag attribute value */ -#define VAL_HILITE (1) /**< ANSI hilite attribute value */ -#define VAL_INVERT (7) /**< ANSI inverse attribute value */ -#define VAL_UNDERSCORE (4) /**< ANSI underscore attribute value */ - -#define COL_BLACK (30) /**< ANSI color black */ -#define COL_RED (31) /**< ANSI color red */ -#define COL_GREEN (32) /**< ANSI color green */ -#define COL_YELLOW (33) /**< ANSI color yellow */ -#define COL_BLUE (34) /**< ANSI color blue */ -#define COL_MAGENTA (35) /**< ANSI color magenta */ -#define COL_CYAN (36) /**< ANSI color cyan */ -#define COL_WHITE (37) /**< ANSI color white */ - -/** The ansi attributes associated with a character. */ -typedef struct { - char flags; /**< Ansi text attributes */ - char fore; /**< Ansi foreground color */ - char back; /**< Ansi background color */ -} ansi_data; - -static void dump_ansi_codes(ansi_data * ad, char *buff, char **bp); - -/** If we're adding y to x, do we need to add z as well? */ -#define EDGE_UP(x,y,z) (((y) & (z)) && !((x) & (z))) - -static void -dump_ansi_codes(ansi_data * ad, char *buff, char **bp) -{ - static ansi_data old_ad = { 0, 0, 0 }; - int f = 0; - - if ((old_ad.fore && !ad->fore) - || (old_ad.back && !ad->back) - || ((old_ad.flags & ad->flags) != old_ad.flags)) { - safe_str(ANSI_NORMAL, buff, bp); - old_ad.flags = 0; - old_ad.fore = 0; - old_ad.back = 0; - } - - if ((old_ad.fore == ad->fore) - && (old_ad.back == ad->back) - && (old_ad.flags == ad->flags)) - /* If nothing has changed, don't bother doing anything. - * This stops the entirely pointless \e[m being generated. */ - return; - - safe_str(ANSI_BEGIN, buff, bp); - - if (EDGE_UP(old_ad.flags, ad->flags, COL_FLASH)) { - if (f++) - safe_chr(';', buff, bp); - safe_integer(VAL_FLASH, buff, bp); - } - - if (EDGE_UP(old_ad.flags, ad->flags, COL_HILITE)) { - if (f++) - safe_chr(';', buff, bp); - safe_integer(VAL_HILITE, buff, bp); - } - - if (EDGE_UP(old_ad.flags, ad->flags, COL_INVERT)) { - if (f++) - safe_chr(';', buff, bp); - safe_integer(VAL_INVERT, buff, bp); - } - - if (EDGE_UP(old_ad.flags, ad->flags, COL_UNDERSCORE)) { - if (f++) - safe_chr(';', buff, bp); - safe_integer(VAL_UNDERSCORE, buff, bp); - } - - if (ad->fore != old_ad.fore) { - if (f++) - safe_chr(';', buff, bp); - safe_integer(ad->fore, buff, bp); - } - - if (ad->back != old_ad.back) { - if (f++) - safe_chr(';', buff, bp); - safe_integer(ad->back + 10, buff, bp); - } - - safe_str(ANSI_END, buff, bp); - - old_ad = *ad; - -} - - -/* ARGSUSED */ -FUNCTION(fun_ansi) -{ - static char tbuff[BUFFER_LEN]; - static ansi_data stack[1024] = { {0, 0, 0} }, *sp = stack; - char const *arg0, *arg1; - char *tbp; - - tbp = tbuff; - arg0 = args[0]; - process_expression(tbuff, &tbp, &arg0, executor, caller, enactor, - PE_DEFAULT, PT_DEFAULT, pe_info); - *tbp = '\0'; - - sp[1] = sp[0]; - sp++; - - for (tbp = tbuff; *tbp; tbp++) { - switch (*tbp) { - case 'n': /* normal */ - sp->flags = 0; - sp->fore = 0; - sp->back = 0; - break; - case 'f': /* flash */ - sp->flags |= COL_FLASH; - break; - case 'h': /* hilite */ - sp->flags |= COL_HILITE; - break; - case 'i': /* inverse */ - sp->flags |= COL_INVERT; - break; - case 'u': /* underscore */ - sp->flags |= COL_UNDERSCORE; - break; - case 'F': /* flash */ - sp->flags &= ~COL_FLASH; - break; - case 'H': /* hilite */ - sp->flags &= ~COL_HILITE; - break; - case 'I': /* inverse */ - sp->flags &= ~COL_INVERT; - break; - case 'U': /* underscore */ - sp->flags &= ~COL_UNDERSCORE; - break; - case 'b': /* blue fg */ - sp->fore = COL_BLUE; - break; - case 'c': /* cyan fg */ - sp->fore = COL_CYAN; - break; - case 'g': /* green fg */ - sp->fore = COL_GREEN; - break; - case 'm': /* magenta fg */ - sp->fore = COL_MAGENTA; - break; - case 'r': /* red fg */ - sp->fore = COL_RED; - break; - case 'w': /* white fg */ - sp->fore = COL_WHITE; - break; - case 'x': /* black fg */ - sp->fore = COL_BLACK; - break; - case 'y': /* yellow fg */ - sp->fore = COL_YELLOW; - break; - case 'B': /* blue bg */ - sp->back = COL_BLUE; - break; - case 'C': /* cyan bg */ - sp->back = COL_CYAN; - break; - case 'G': /* green bg */ - sp->back = COL_GREEN; - break; - case 'M': /* magenta bg */ - sp->back = COL_MAGENTA; - break; - case 'R': /* red bg */ - sp->back = COL_RED; - break; - case 'W': /* white bg */ - sp->back = COL_WHITE; - break; - case 'X': /* black bg */ - sp->back = COL_BLACK; - break; - case 'Y': /* yellow bg */ - sp->back = COL_YELLOW; - break; - } - } - - dump_ansi_codes(sp, buff, bp); - - arg1 = args[1]; - process_expression(buff, bp, &arg1, executor, caller, enactor, - PE_DEFAULT, PT_DEFAULT, pe_info); - - dump_ansi_codes(--sp, buff, bp); - -} - -/* ARGSUSED */ -FUNCTION(fun_stripansi) -{ - /* Strips ANSI codes away from a given string of text. Starts by - * finding the '\x' character and stripping until it hits an 'm'. - */ - - char *cp; - - cp = remove_markup(args[0], NULL); - safe_str(cp, buff, bp); -} - -/* ARGSUSED */ FUNCTION(fun_edit) { - int i; - char *f, *r, *raw; - ansi_string *prebuf; - char postbuf[BUFFER_LEN], lastbuf[BUFFER_LEN], *postp; - size_t rlen, flen; - - prebuf = parse_ansi_string(args[0]); - raw = args[0]; - for (i = 1; i < nargs - 1; i += 2) { - - postp = postbuf; - f = args[i]; /* find this */ - r = args[i + 1]; /* replace it with this */ - flen = arglens[i]; - rlen = arglens[i + 1]; + int i, j; + char *needle; + size_t nlen; + char *search, *ptr; + ansi_string *orig, *repl; - /* Check for nothing to avoid infinite loop */ - if (!*f && !*r) - continue; + orig = parse_ansi_string(args[0]); - if (flen == 1 && *f == '$') { - /* append */ - safe_str(raw, postbuf, &postp); - safe_strl(r, rlen, postbuf, &postp); - } else if (flen == 1 && *f == '^') { - /* prepend */ - safe_strl(r, rlen, postbuf, &postp); - safe_str(raw, postbuf, &postp); - } else if (!*f) { - /* insert between every character */ - size_t last; - safe_strl(r, rlen, postbuf, &postp); - for (last = 0; last < prebuf->len; last++) { - safe_ansi_string(prebuf, last, 1, postbuf, &postp); - safe_strl(r, rlen, postbuf, &postp); + for (i = 1; i < nargs - 1; i += 2) { + needle = remove_markup(args[i], &nlen); + nlen--; + repl = parse_ansi_string(args[i + 1]); + if (strcmp(needle, "$") == 0) { + ansi_string_insert(orig, orig->len, repl); + } else if (strcmp(needle, "^") == 0) { + ansi_string_insert(orig, 0, repl); + } else if (nlen == 0) { + /* Annoying. Stick repl between each character */ + /* Since this is inserts, we're working *backwards* */ + for (j = orig->len - 1; j > 0; j--) { + ansi_string_insert(orig, j, repl); } } else { - char *p; - size_t last = 0; - - while (last < prebuf->len && (p = strstr(prebuf->text + last, f)) != NULL) { - safe_ansi_string(prebuf, last, p - (prebuf->text + last), - postbuf, &postp); - safe_strl(r, rlen, postbuf, &postp); - last = p - prebuf->text + flen; + search = orig->text; + /* Find each occurrence */ + while ((ptr = strstr(search, needle)) != NULL) { + /* Perform the replacement */ + ansi_string_replace(orig, ptr - orig->text, nlen, repl); + search = ptr + repl->len; } - if (last < prebuf->len) - safe_ansi_string(prebuf, last, prebuf->len, postbuf, &postp); } - *postp = '\0'; - free_ansi_string(prebuf); - prebuf = parse_ansi_string(postbuf); - strcpy(lastbuf, postbuf); - raw = lastbuf; - } - safe_ansi_string(prebuf, 0, prebuf->len, buff, bp); - free_ansi_string(prebuf); + free_ansi_string(repl); + optimize_ansi_string(orig); + } + + safe_ansi_string(orig, 0, orig->len, buff, bp); + free_ansi_string(orig); } FUNCTION(fun_brackets) @@ -1786,46 +1587,36 @@ FUNCTION(fun_brackets) lbrace, rbrace, lcurl, rcurl); } - -/* Returns the length of str up to the first return character, - * or else the last space, or else 0. +/* Returns the length of str up to the first return character, + * or else the last space, or else -1. */ static int -wraplen(char *str, int maxlen) +wraplen(char *str, size_t maxlen) { - const int length = strlen(str); - int i = 0; + size_t i, length; - if (length <= maxlen) { - /* Find the first return char - * so %r will not mess with any alignment - * functions. - */ - while (i < length) { - if ((str[i] == '\n') || (str[i] == '\r')) - return i; - i++; - } - return length; - } + /* If the remaining text is shorter than our chunk size (maxlen), + * try to return it all. Otherwise, scan the maximum allowable size, + * but account for a newline character. */ + length = (strlen(str) <= maxlen) ? strlen(str) : maxlen + 1; - /* Find the first return char - * so %r will not mess with any alignment - * functions. - */ - while (i <= maxlen + 1) { + /* If there's a newline in the chunk, wrap there. */ + for (i = 0; i < length; i++) if ((str[i] == '\n') || (str[i] == '\r')) return i; - i++; - } - /* No return char was found. Now - * find the last space in str. - */ + /* No newlines, but the text we can grab will fit on one line */ + if (length == strlen(str)) + return length; + + /* No return char was found, so find the last space in str. */ while (str[maxlen] != ' ' && maxlen > 0) maxlen--; - return (maxlen ? maxlen : -1); + if (maxlen > 0) + return (int) maxlen; + else + return -1; } /** The integer in string a will be stored in v, @@ -1841,7 +1632,7 @@ wraplen(char *str, int maxlen) return; \ } \ v = parse_integer(args[a]); \ - } \ + } \ while (0) FUNCTION(fun_wrap) @@ -1855,16 +1646,24 @@ FUNCTION(fun_wrap) char *pstr; /* start of string */ ansi_string *as; const char *pend; /* end of string */ - int linewidth, width1st, width; + size_t linewidth, width1st, width; int linenr = 0; const char *linesep; - int ansiwidth, ansilen; + size_t ansiwidth; + int ansilen; if (!args[0] || !*args[0]) return; + if (ansi_strlen(args[0]) == 0) { + safe_str(args[0], buff, bp); + return; + } + + initint(1, width, 72); width1st = width; + if (nargs > 2) initint(2, width1st, width); if (nargs > 3) @@ -1884,23 +1683,26 @@ FUNCTION(fun_wrap) pend = as->text + as->len; linewidth = width1st; + while (pstr < pend) { if (linenr++ == 1) linewidth = width; if ((linenr > 1) && linesep && *linesep) safe_str(linesep, buff, bp); - ansiwidth = ansi_strnlen(pstr, linewidth); + ansiwidth = strlen(pstr); + if (ansiwidth > linewidth) + ansiwidth = linewidth; ansilen = wraplen(pstr, ansiwidth); if (ansilen < 0) { /* word doesn't fit on one line, so cut it */ - safe_ansi_string2(as, pstr - as->text, ansiwidth - 1, buff, bp); + safe_ansi_string(as, pstr - as->text, ansiwidth - 1, buff, bp); safe_chr('-', buff, bp); pstr += ansiwidth - 1; /* move to start of next line */ } else { /* normal line */ - safe_ansi_string2(as, pstr - as->text, ansilen, buff, bp); + safe_ansi_string(as, pstr - as->text, ansilen, buff, bp); if (pstr[ansilen] == '\r') ++ansilen; pstr += ansilen + 1; /* move to start of next line */ @@ -1915,6 +1717,8 @@ FUNCTION(fun_wrap) #define AL_RIGHT 2 /**< Align right */ #define AL_CENTER 3 /**< Align center */ #define AL_REPEAT 4 /**< Repeat column */ +#define AL_COALESCE_LEFT 8 /**< Coalesce empty column with column to left */ +#define AL_COALESCE_RIGHT 16 /**< Coalesce empty column with column to right */ static int align_one_line(char *buff, char **bp, int ncols, @@ -1938,9 +1742,43 @@ align_one_line(char *buff, char **bp, int ncols, memset(line, filler, BUFFER_LEN); cols_done = 0; for (i = 0; i < ncols; i++) { + /* Skip 0-width and negative columns */ + if (cols[i] <= 0) { + cols_done++; + continue; + } + /* Is the next column AL_COALESCE_LEFT and has it run out of + * text? If so, do the coalesce now. + */ + if ((i < (ncols - 1)) && + (cols[i + 1] > 0) && + (!(calign[i + 1] & AL_REPEAT) && + (calign[i + 1] & AL_COALESCE_LEFT) && + (!ptrs[i + 1] || !*ptrs[i + 1]))) { + /* To coalesce left on this line, modify the left column's + * width and set the current column width to 0 (which we can + * teach it to skip). */ + cols[i] += cols[i + 1] + fslen; + cols[i + 1] = 0; + } if (!ptrs[i] || !*ptrs[i]) { if (calign[i] & AL_REPEAT) { ptrs[i] = as[i]->text; + /* To coalesce right on this line, + * modify the current column's width to 0, modify the right + * column's width, and continue on to processing the next + * column + */ + } else if (calign[i] & AL_COALESCE_RIGHT) { + for (j = i + 1; j < ncols; j++) { + if (cols[j] > 0) { + cols[j] += cols[i] + fslen; + break; + } + } + cols[i] = 0; + cols_done++; + continue; } else { lp += cols[i]; if (i < (ncols - 1) && fslen) @@ -1963,7 +1801,7 @@ align_one_line(char *buff, char **bp, int ncols, sp = segment; if (!*ptr) { if (len > 0) { - safe_ansi_string2(as[i], ptrs[i] - (as[i]->text), len, segment, &sp); + safe_ansi_string(as[i], ptrs[i] - (as[i]->text), len, segment, &sp); } ptrs[i] = ptr; } else if (*ptr == '\n') { @@ -1971,7 +1809,7 @@ align_one_line(char *buff, char **bp, int ncols, *tptr && tptr >= ptrs[i] && isspace((unsigned char) *tptr); tptr--) ; len = (tptr - ptrs[i]) + 1; if (len > 0) { - safe_ansi_string2(as[i], ptrs[i] - (as[i]->text), len, segment, &sp); + safe_ansi_string(as[i], ptrs[i] - (as[i]->text), len, segment, &sp); } ptrs[i] = ptr + 1; ptr = tptr; @@ -1982,12 +1820,12 @@ align_one_line(char *buff, char **bp, int ncols, *tptr && tptr >= ptrs[i] && isspace((unsigned char) *tptr); tptr--) ; len = (tptr - ptrs[i]) + 1; if (len > 0) { - safe_ansi_string2(as[i], ptrs[i] - (as[i]->text), len, segment, &sp); + safe_ansi_string(as[i], ptrs[i] - (as[i]->text), len, segment, &sp); } ptrs[i] = lastspace; } else { if (len > 0) { - safe_ansi_string2(as[i], ptrs[i] - (as[i]->text), len, segment, &sp); + safe_ansi_string(as[i], ptrs[i] - (as[i]->text), len, segment, &sp); } ptrs[i] = ptr; } @@ -2014,8 +1852,11 @@ align_one_line(char *buff, char **bp, int ncols, *ptrs[i] && (*ptrs[i] != '\n') && isspace((unsigned char) *ptrs[i]); ptrs[i]++) ; } + if (cols_done == ncols) return 0; + if ((lp - line) > BUFFER_LEN) + lp = (line + BUFFER_LEN - 1); *lp = '\0'; if (linenum > 0 && lslen > 0) safe_str(linesep, buff, bp); @@ -2039,6 +1880,7 @@ FUNCTION(fun_align) int fslen; char *linesep; int lslen; + int totallen = 0; filler = ' '; fieldsep = (char *) " "; @@ -2072,16 +1914,34 @@ FUNCTION(fun_align) calign[ncols] |= AL_REPEAT; ptr++; } + if (*ptr == '`') { + calign[ncols] |= AL_COALESCE_LEFT; + ptr++; + } + if (*ptr == '\'') { + calign[ncols] |= AL_COALESCE_RIGHT; + ptr++; + } cols[ncols++] = i; if (!*ptr) break; } + for (i = 0; i < ncols; i++) { - if (cols[i] < 1) { - safe_str(T("#-1 CANNOT HAVE COLUMN OF SIZE 0"), buff, bp); + if (cols[i] < 0) { + safe_str(T("#-1 CANNOT HAVE COLUMNS OF NEGATIVE SIZE"), buff, bp); + return; + } + if (cols[i] > BUFFER_LEN) { + safe_str(T("#-1 CANNOT HAVE COLUMNS THAT LARGE"), buff, bp); return; } + totallen += cols[i]; + } + if (totallen > BUFFER_LEN) { + safe_str(T("#-1 CANNOT HAVE COLUMNS THAT LARGE"), buff, bp); + return; } if (ncols < 1) { @@ -2141,26 +2001,32 @@ FUNCTION(fun_speak) { ufun_attrib transufun; ufun_attrib nullufun; - dbref speaker; + dbref speaker = NOTHING; char *speaker_str; + const char *speaker_name; char *open, *close; - int transform = 0, null = 0, say = 0; + char *start, *end = NULL; + bool transform = 0, null = 0, say = 0; char *wenv[3]; int funccount; int fragment = 0; char *say_string; char *string; char rbuff[BUFFER_LEN]; - OOREF_DECL; - speaker = match_thing(executor, args[0]); - if (speaker == NOTHING || speaker == AMBIGUOUS) { - safe_str(T(e_match), buff, bp); - return; + if (*args[0] == '&') { + speaker_str = args[0]; + speaker_name = args[0] + 1; + } else { + speaker = match_thing(executor, args[0]); + if (speaker == NOTHING || speaker == AMBIGUOUS) { + safe_str(T(e_match), buff, bp); + return; + } + speaker_str = unparse_dbref(speaker); + speaker_name = accented_name(speaker); } - speaker_str = unparse_dbref(speaker); - if (!args[1] || !*args[1]) return; @@ -2171,24 +2037,20 @@ FUNCTION(fun_speak) else say_string = (char *) "says,"; - ENTER_OOREF; - if (nargs > 3) { - if (args[3] != '\0') { + if (args[3]) { /* we have a transform attr */ transform = 1; if (!fetch_ufun_attrib(args[3], executor, &transufun, 1)) { safe_str(T(e_atrperm), buff, bp); - LEAVE_OOREF; return; } if (nargs > 4) { - if (args[4] != '\0') { + if (args[4]) { /* we have an attr to use when transform returns an empty string */ null = 1; if (!fetch_ufun_attrib(args[4], executor, &nullufun, 1)) { safe_str(T(e_atrperm), buff, bp); - LEAVE_OOREF; return; } } @@ -2196,11 +2058,11 @@ FUNCTION(fun_speak) } } - if (nargs < 6 || args[5] == '\0') + if (nargs < 6 || !args[5]) open = (char *) "\""; else open = args[5]; - if (nargs < 7 || args[6] == '\0') + if (nargs < 7 || !args[6]) close = open; else close = args[6]; @@ -2208,18 +2070,21 @@ FUNCTION(fun_speak) switch (*string) { case ':': - safe_str(accented_name(speaker), buff, bp); + safe_str(speaker_name, buff, bp); string++; if (*string == ' ') { /* semipose it instead */ while (*string == ' ') string++; + /* Penn: : foo -> Name foo. Tiny: : foo -> Namefoo */ + if (!strcmp(called_as, "SPEAKPENN")) + safe_chr(' ', buff, bp); } else safe_chr(' ', buff, bp); break; case ';': string++; - safe_str(accented_name(speaker), buff, bp); + safe_str(speaker_name, buff, bp); if (*string == ' ') { /* pose it instead */ safe_chr(' ', buff, bp); @@ -2238,101 +2103,99 @@ FUNCTION(fun_speak) break; } - if (!transform || (!say && !strstr(string, open))) { + start = strstr(string, open); + + if (!transform || (!say && !start)) { /* nice and easy */ if (say) - safe_format(buff, bp, "%s %s \"%s\"", accented_name(speaker), - say_string, string); + safe_format(buff, bp, "%s %s \"%s\"", speaker_name, say_string, string); else safe_str(string, buff, bp); - LEAVE_OOREF; return; } + /* If we're in say mode, prefix the buffer */ + if (say) { + if (speaker != NOTHING) + safe_str(accented_name(speaker), buff, bp); + else + safe_str(speaker_name, buff, bp); + safe_chr(' ', buff, bp); + safe_str(say_string, buff, bp); + safe_chr(' ', buff, bp); + fragment = -1; + /* Special case: In say mode, if the delim isn't a quote, then + * we just pretend that we're otherwise in pose mode + */ + if (strcmp(open, "\"")) { + say = 0; + } + } + + /* If the first char of the string is an open quote, copy it, + * skip it, and we're good to transform. Otherwise, if + * we're not in say mode, copy up to the first open quote + * and then transform. There must be an open quote somewhere + * if we're not in say mode. + */ + if (string_prefix(string, open)) { + if (say) + safe_str(open, buff, bp); + start += strlen(open); + } else if (!say && start) { + /* start points to first open quote, and after first char */ + safe_str(chopstr(string, start - string + 1), buff, bp); + fragment = 0; + /* Don't add the quote in */ + start += strlen(open); + } else { + /* We're in say mode and the first char isn't open, start there */ + start = string; + } - if (say && !strstr(string, close)) { - /* the whole string has to be transformed */ - wenv[0] = string; + funccount = pe_info->fun_invocations; + while (start && *start) { + fragment++; + /* Transform to the next close, or to the end of the string. */ + if ((end = strstr(start, close)) != NULL) + *end++ = '\0'; + wenv[0] = start; wenv[1] = speaker_str; wenv[2] = unparse_integer(fragment); - if (call_ufun(&transufun, wenv, 3, rbuff, executor, enactor, pe_info)) { - LEAVE_OOREF; - return; - } - if (strlen(rbuff) > 0) { - safe_format(buff, bp, "%s %s %s", accented_name(speaker), say_string, rbuff); - LEAVE_OOREF; - return; - } else if (null == 1) { + if (call_ufun(&transufun, wenv, 3, rbuff, executor, enactor, pe_info)) + break; + funccount = pe_info->fun_invocations; + if (!*rbuff && (null == 1)) { wenv[0] = speaker_str; wenv[1] = unparse_integer(fragment); - if (call_ufun(&nullufun, wenv, 2, rbuff, executor, enactor, pe_info)) { - LEAVE_OOREF; - return; - } - safe_str(rbuff, buff, bp); - LEAVE_OOREF; - return; - } - } else { - /* only transform portions of string between open and close */ - char *speech; - int indx; - int finished = 0; - int delete = 0; - - if (say) { - safe_str(accented_name(speaker), buff, bp); - safe_chr(' ', buff, bp); - safe_str(say_string, buff, bp); - safe_chr(' ', buff, bp); - } - funccount = pe_info->fun_invocations; - while (!finished && ((say && fragment == 0 && (speech = string)) - || (speech = strstr(string, open)))) { - fragment++; - indx = string - speech; - if (indx < 0) - indx *= -1; - if (string != NULL && strlen(string) > 0 && indx > 0) - safe_strl(string, indx, buff, bp); - if (!say || fragment > 1) - speech = speech + strlen(open); /* move past open char */ - /* find close-char */ - string = strstr(speech, close); - if (!string || !(string = string + strlen(close))) { - /* no close char, or nothing after it; we're at the end! */ - finished = 1; - } - delete = (string == NULL ? strlen(speech) : strlen(speech) - - (strlen(string) + strlen(close))); - speech = chopstr(speech, delete); - wenv[0] = speech; - wenv[1] = speaker_str; - wenv[2] = unparse_integer(fragment); - if (call_ufun(&transufun, wenv, 3, rbuff, executor, enactor, pe_info)) - break; - if (*bp == (buff + BUFFER_LEN - 1) && - pe_info->fun_invocations == funccount) - break; - funccount = pe_info->fun_invocations; - if ((null == 1) && (strlen(rbuff) == 0)) { - wenv[0] = speaker_str; - wenv[1] = unparse_integer(fragment); - if (call_ufun(&nullufun, wenv, 2, rbuff, executor, enactor, pe_info)) - break; - } - if (strlen(rbuff) > 0) { - safe_str(rbuff, buff, bp); - } - if (*bp == (buff + BUFFER_LEN - 1) && - pe_info->fun_invocations == funccount) + if (call_ufun(&nullufun, wenv, 2, rbuff, executor, enactor, pe_info)) break; } - if (string != NULL && strlen(string) > 0) { - safe_str(string, buff, bp); /* remaining string (not speech, so not t) */ + if (*rbuff) + safe_str(rbuff, buff, bp); + if (((*bp - buff) >= BUFFER_LEN - 1) && + (pe_info->fun_invocations == funccount)) + break; + if (end && *end) { + if (say) + safe_str(close, buff, bp); } + if (!end || !*end) + break; + start = strstr(end, open); + if (start) { + /* Copy text not being transformed. */ + if (start && *start && (start - end > (ptrdiff_t) strlen(open))) + safe_str(chopstr(end, start - end + 1), buff, bp); + start += strlen(open); + } else { + /* No more opens, so we're done, and end has the rest */ + break; + } + if (((*bp - buff) >= BUFFER_LEN - 1) && + (pe_info->fun_invocations == funccount)) + break; } - - LEAVE_OOREF; + if (end && *end) + safe_str(end, buff, bp); } diff --git a/src/funtime.c b/src/funtime.c index 048161f..94a0a9c 100644 --- a/src/funtime.c +++ b/src/funtime.c @@ -20,10 +20,10 @@ #include "externs.h" #include "parse.h" #include "dbdefs.h" -#include "attrib.h" #include "log.h" #include "match.h" #include "attrib.h" +#include "attrib.h" #include "confmagic.h" int do_convtime(const char *str, struct tm *ttm); @@ -37,7 +37,7 @@ FUNCTION(fun_timefmt) char s[BUFFER_LEN]; struct tm *ttm; time_t tt; - int len, n; + size_t len, n; if (!args[0] || !*args[0]) return; /* No field? Bad user. */ @@ -87,6 +87,7 @@ FUNCTION(fun_timefmt) * trying to figure out which of the two cases happened, just * return an empty string. */ + safe_str(T("#-1 COULDN'T FORMAT TIME"), buff, bp); return; } for (n = 0; n < len; n++) @@ -200,7 +201,7 @@ FUNCTION(fun_etimefmt) return; } - secs = parse_uinteger(args[1]); + secs = strtoul(args[1], NULL, 10); do_timestring(buff, bp, args[0], secs); @@ -267,56 +268,11 @@ etime_to_secs(char *str1, int *secs) /* ARGSUSED */ FUNCTION(fun_stringsecs) { - /* parse the result from timestring() back into a number of seconds */ - - int secs = 0; - char *str1 = args[0]; - char str2[BUFFER_LEN]; - int i; - - while (str1 && *str1) { - while (*str1 == ' ') - str1++; - i = 0; - while (isdigit((unsigned char) *str1)) { - str2[i] = *str1; - str1++; - i++; - } - if (i == 0) { - safe_str(T("#-1 INVALID TIMESTRING"), buff, bp); /* no numbers */ - return; - } - str2[i] = '\0'; - if (!*str1) { - secs += parse_integer(str2); /* no more chars, just add seconds and stop */ - break; - } - switch (*str1) { - case 'd': - case 'D': - secs += (parse_integer(str2) * 86400); /* days */ - break; - case 'h': - case 'H': - secs += (parse_integer(str2) * 3600); /* hours */ - break; - case 'm': - case 'M': - secs += (parse_integer(str2) * 60); /* minutes */ - break; - case 's': - case 'S': - case ' ': - secs += parse_integer(str2); /* seconds */ - break; - default: - safe_str(T("#-1 INVALID TIMESTRING"), buff, bp); - return; - } - str1++; /* move past the time char */ - } - safe_integer(secs, buff, bp); + int secs; + if (etime_to_secs(args[0], &secs)) + safe_integer(secs, buff, bp); + else + safe_str(T("#-1 INVALID TIMESTRING"), buff, bp); } /* ARGSUSED */ @@ -548,12 +504,12 @@ FUNCTION(fun_isdaylight) void do_timestring(char *buff, char **bp, const char *format, unsigned long secs) { - int days, hours, mins; + unsigned long days, hours, mins; int pad = 0; int width; const char *c; char *w; - int include_suffix, even_if_0, in_format_flags; + bool include_suffix, in_format_flags, even_if_0; days = secs / 86400; secs %= 86400; @@ -565,7 +521,7 @@ do_timestring(char *buff, char **bp, const char *format, unsigned long secs) for (c = format; c && *c; c++) { if (*c == '$') { c++; - width = strtol(c, &w, 10); + width = parse_int(c, &w, 10); if (c == w) pad = 0; else @@ -623,9 +579,9 @@ do_timestring(char *buff, char **bp, const char *format, unsigned long secs) in_format_flags = 0; if (mins || even_if_0) { if (pad) - safe_format(buff, bp, "%*d", width, mins); + safe_format(buff, bp, "%*lu", width, mins); else - safe_integer(mins, buff, bp); + safe_uinteger(mins, buff, bp); if (include_suffix) safe_chr('m', buff, bp); } else if (pad) @@ -635,9 +591,9 @@ do_timestring(char *buff, char **bp, const char *format, unsigned long secs) in_format_flags = 0; if (mins || even_if_0) { if (pad) - safe_format(buff, bp, "%0*d", width, mins); + safe_format(buff, bp, "%0*lu", width, mins); else - safe_format(buff, bp, "%0d", mins); + safe_format(buff, bp, "%0lu", mins); if (include_suffix) safe_chr('m', buff, bp); } else if (pad) @@ -647,9 +603,9 @@ do_timestring(char *buff, char **bp, const char *format, unsigned long secs) in_format_flags = 0; if (hours || even_if_0) { if (pad) - safe_format(buff, bp, "%*d", width, hours); + safe_format(buff, bp, "%*lu", width, hours); else - safe_integer(hours, buff, bp); + safe_uinteger(hours, buff, bp); if (include_suffix) safe_chr('h', buff, bp); } else if (pad) @@ -659,9 +615,9 @@ do_timestring(char *buff, char **bp, const char *format, unsigned long secs) in_format_flags = 0; if (hours || even_if_0) { if (pad) - safe_format(buff, bp, "%0*d", width, hours); + safe_format(buff, bp, "%0*lu", width, hours); else - safe_format(buff, bp, "%0d", hours); + safe_format(buff, bp, "%0lu", hours); if (include_suffix) safe_chr('h', buff, bp); } else if (pad) @@ -671,9 +627,9 @@ do_timestring(char *buff, char **bp, const char *format, unsigned long secs) in_format_flags = 0; if (days || even_if_0) { if (pad) - safe_format(buff, bp, "%*d", width, days); + safe_format(buff, bp, "%*lu", width, days); else - safe_integer(days, buff, bp); + safe_uinteger(days, buff, bp); if (include_suffix) safe_chr('d', buff, bp); } else if (pad) @@ -683,9 +639,9 @@ do_timestring(char *buff, char **bp, const char *format, unsigned long secs) in_format_flags = 0; if (days || even_if_0) { if (pad) - safe_format(buff, bp, "%0*d", width, days); + safe_format(buff, bp, "%0*lu", width, days); else - safe_format(buff, bp, "%0d", days); + safe_format(buff, bp, "%0lu", days); if (include_suffix) safe_chr('d', buff, bp); } else if (pad) diff --git a/src/funufun.c b/src/funufun.c index 1499e87..15474ba 100644 --- a/src/funufun.c +++ b/src/funufun.c @@ -23,7 +23,7 @@ void do_userfn(char *buff, char **bp, dbref obj, ATTR *attrib, int nargs, char **args, dbref executor, dbref caller, dbref enactor, - PE_Info * pe_info); + PE_Info *pe_info, int extra_flags); /* ARGSUSED */ FUNCTION(fun_s) @@ -34,6 +34,35 @@ FUNCTION(fun_s) PT_DEFAULT, pe_info); } +/* ARGSUSED */ +FUNCTION(fun_fn) +{ + /* First argument is name of a function, remaining are arguments + * for that function. + */ + char tbuf[BUFFER_LEN]; + char *tp = tbuf; + char const *p; + int i; + if (!args[0] || !*args[0]) + return; /* No function name */ + /* Evaluate first argument */ + p = args[0]; + process_expression(tbuf, &tp, &p, executor, caller, + enactor, PE_DEFAULT, PT_DEFAULT, pe_info); + safe_chr('(', tbuf, &tp); + for (i = 1; i < nargs; i++) { + if (i > 1) + safe_chr(',', tbuf, &tp); + safe_strl(args[i], arglens[i], tbuf, &tp); + } + safe_chr(')', tbuf, &tp); + *tp = '\0'; + p = tbuf; + process_expression(buff, bp, &p, executor, caller, enactor, + PE_DEFAULT | PE_BUILTINONLY, PT_DEFAULT, pe_info); +} + /* ARGSUSED */ FUNCTION(fun_localize) { @@ -108,13 +137,14 @@ FUNCTION(fun_objeval) void do_userfn(char *buff, char **bp, dbref obj, ATTR *attrib, int nargs, char **args, dbref executor, dbref caller - __attribute__ ((__unused__)), dbref enactor, PE_Info * pe_info) + __attribute__ ((__unused__)), dbref enactor, PE_Info * pe_info, + int extra_flags) { int j; char *tptr[10]; char *tbuf; char const *tp; - int pe_flags = PE_DEFAULT; + int pe_flags = PE_DEFAULT | extra_flags; int old_args; /* save our stack */ @@ -260,10 +290,9 @@ FUNCTION(fun_uldefault) * pass them to the function */ xargs = NULL; if (nargs > 2) { - xargs = - (char **) mush_malloc((nargs - 2) * sizeof(char *), "udefault.xargs"); + xargs = mush_calloc(nargs - 2, sizeof(char *), "udefault.xargs"); for (i = 0; i < nargs - 2; i++) { - xargs[i] = (char *) mush_malloc(BUFFER_LEN, "udefault"); + xargs[i] = mush_malloc(BUFFER_LEN, "udefault"); dp = xargs[i]; sp = args[i + 2]; process_expression(xargs[i], &dp, &sp, executor, caller, enactor, @@ -274,7 +303,7 @@ FUNCTION(fun_uldefault) if (called_as[1] == 'L') save_global_regs("uldefault.save", preserve); do_userfn(buff, bp, thing, attrib, nargs - 2, xargs, - executor, caller, enactor, pe_info); + executor, caller, enactor, pe_info, 0); if (called_as[1] == 'L') restore_global_regs("uldefault.save", preserve); @@ -328,7 +357,7 @@ FUNCTION(fun_zfun) return; } do_userfn(buff, bp, zone, attrib, nargs - 1, args + 1, executor, caller, - enactor, pe_info); + enactor, pe_info, 0); LEAVE_OOREF; return; } else if (attrib || !Can_Examine(executor, zone)) { diff --git a/src/game.c b/src/game.c index c17070f..aab34a8 100644 --- a/src/game.c +++ b/src/game.c @@ -16,11 +16,11 @@ #ifdef I_STDARG #include #endif -#ifdef I_SYS_WAIT -#include -#endif #ifdef I_SYS_TIME #include +#ifdef TIME_WITH_SYS_TIME +#include +#endif #else #include #endif @@ -33,7 +33,7 @@ void Win32MUSH_setup(void); #ifdef I_SYS_TYPES #include #endif -#ifdef HAS_GETRUSAGE +#ifdef HAVE_SYS_RESOURCE_H #include #endif #include @@ -66,6 +66,7 @@ void Win32MUSH_setup(void); #include "command.h" #include "htab.h" #include "ptab.h" +#include "intmap.h" #include "log.h" #include "lock.h" #include "dbdefs.h" @@ -73,7 +74,11 @@ void Win32MUSH_setup(void); #include "function.h" #include "help.h" #include "dbio.h" -#include "pcre.h" +#include "mypcre.h" +#ifndef WIN32 +#include "wait.h" +#endif +#include "ansi.h" #include "modules.h" #ifdef hpux @@ -82,25 +87,17 @@ void Win32MUSH_setup(void); #endif /* fix to HP-UX getrusage() braindamage */ #include "confmagic.h" -#ifdef HAS_WAITPID -/** Return value of wait* functions */ -#define WAIT_TYPE int -#else -#ifdef UNION_WAIT -#define WAIT_TYPE union wait -#else -#define WAIT_TYPE int -#endif -#endif /* declarations */ GLOBALTAB globals = { 0, "", 0, 0, 0, 0, 0, 0, 0, 0 }; + static int epoch = 0; static int reserved; /**< Reserved file descriptor */ int depth = 0; /**< excessive recursion prevention */ -static dbref *errdblist = NULL; /**< List of dbrefs to return errors from */ -static dbref *errdbtail; /**< Pointer to end of errdblist */ -static int errdbsize = 4; /**< Current size of errdblist array */ +static dbref *errdblist = NULL; /**< List of dbrefs to return errors from */ +static dbref *errdbtail = NULL; /**< Pointer to end of errdblist */ +#define ERRDB_INITIAL_SIZE 5 +static int errdbsize = ERRDB_INITIAL_SIZE; /**< Current size of errdblist array */ extern int use_flagfile; extern struct module_entry_t *module_list; @@ -109,14 +106,14 @@ static void errdb_grow(void); extern void initialize_mt(void); extern const unsigned char *tables; extern void conf_default_set(void); -static int dump_database_internal(void); +static bool dump_database_internal(void); static FILE *db_open(const char *filename); static FILE *db_open_write(const char *filename); static void db_close(FILE * f); static int fail_commands(dbref player); void do_readcache(dbref player); int check_alias(const char *command, const char *list); -int list_check(dbref thing, dbref player, char type, +static int list_check(dbref thing, dbref player, char type, char end, char *str, int just_match); int alias_list_check(dbref thing, const char *command, const char *type); int loc_alias_check(dbref loc, const char *command, const char *type); @@ -128,13 +125,14 @@ void do_scan(dbref player, char *command, int flag); void do_list(dbref player, char *arg, int lc); void do_dolist(dbref player, char *list, char *command, dbref cause, unsigned int flags); -void do_uptime(dbref player, int mortal); +void do_uptime(dbref player); static char *make_new_epoch_file(const char *basename, int the_epoch); #ifdef HAS_GETRUSAGE void rusage_stats(void); #endif void do_list_memstats(dbref player); +void do_list_allocations(dbref player); void st_stats_header(dbref player); void st_stats(dbref player, StrTree *root, const char *name); void do_timestring(char *buff, char **bp, const char *format, @@ -157,7 +155,7 @@ extern int start_cron(void); #endif /* MUSHCRON */ -Pid_t forked_dump_pid = -1; +pid_t forked_dump_pid = -1; /** Open /dev/null to reserve a file descriptor that can be reused later. */ void @@ -307,11 +305,6 @@ do_shutdown(dbref player, enum shutdown_type flag) do_log(LT_ERR, player, NOTHING, T("SHUTDOWN by %s(%s)\n"), Name(player), unparse_dbref(player)); - /* This will create a file used to check if a restart should occur */ -#ifdef AUTORESTART - system("touch NORESTART"); -#endif - if (flag == SHUT_PANIC) { mush_panic("@shutdown/panic"); } else { @@ -328,7 +321,7 @@ do_shutdown(dbref player, enum shutdown_type flag) jmp_buf db_err; -static int +static bool dump_database_internal(void) { char realdumpfile[2048]; @@ -344,7 +337,7 @@ dump_database_internal(void) ignore_signal(SIGPROF); #endif #endif -#ifdef I_SETJMP + if (setjmp(db_err)) { /* The dump failed. Disk might be full or something went bad with the compression slave. Boo! */ @@ -356,7 +349,7 @@ dump_database_internal(void) install_sig_handler(SIGPROF, signal_cpu_limit); #endif #endif - return 1; + return false; } else { /* Replacement local_dump_database */ MODULE_ITER(m) @@ -379,11 +372,11 @@ dump_database_internal(void) unlink(realdumpfile); #endif if(rename(realtmpfl, realdumpfile) < 0) { - perror(realtmpfl); + penn_perror(realtmpfl); longjmp(db_err, 1); } } else { - perror(realtmpfl); + penn_perror(realtmpfl); longjmp(db_err, 1); } } @@ -414,11 +407,11 @@ dump_database_internal(void) unlink(realdumpfile); #endif if (rename(realtmpfl, realdumpfile) < 0) { - perror(realtmpfl); + penn_perror(realtmpfl); longjmp(db_err, 1); } } else { - perror(realtmpfl); + penn_perror(realtmpfl); longjmp(db_err, 1); } #ifdef USE_MAILER @@ -433,11 +426,11 @@ dump_database_internal(void) unlink(realdumpfile); #endif if (rename(realtmpfl, realdumpfile) < 0) { - perror(realtmpfl); + penn_perror(realtmpfl); longjmp(db_err, 1); } } else { - perror(realtmpfl); + penn_perror(realtmpfl); longjmp(db_err, 1); } } @@ -453,25 +446,24 @@ dump_database_internal(void) unlink(realdumpfile); #endif if (rename(realtmpfl, realdumpfile) < 0) { - perror(realtmpfl); + penn_perror(realtmpfl); longjmp(db_err, 1); } } else { - perror(realtmpfl); + penn_perror(realtmpfl); longjmp(db_err, 1); } #endif /* CHAT_SYSTEM */ time(&globals.last_dump_time); } -#endif #ifndef PROFILING #ifdef HAS_ITIMER install_sig_handler(SIGPROF, signal_cpu_limit); #endif #endif - return 0; + return true; } /** Crash gracefully. @@ -574,7 +566,7 @@ dump_database(void) epoch++; do_rawlog(LT_ERR, "DUMPING: %s.#%d#", globals.dumpfile, epoch); - if (!dump_database_internal()) + if (dump_database_internal()) do_rawlog(LT_ERR, "DUMPING: %s.#%d# (done)", globals.dumpfile, epoch); } @@ -590,9 +582,10 @@ dump_database(void) void fork_and_dump(int forking) { - int child, nofork, status, split; + pid_t child; + bool nofork, status, split; epoch++; -#if (MALLOC_PACKAGE == 2) + #if (MALLOC_PACKAGE == 2) FILE *memory_file; #endif @@ -600,12 +593,12 @@ fork_and_dump(int forking) chunk_stats(NOTHING, 0); chunk_stats(NOTHING, 1); #endif - do_rawlog(LT_CHECK, "CHECKPOINTING: %s.#%d#\n", globals.dumpfile, epoch); + do_rawlog(LT_CHECK, "CHECKPOINTING: %s.#%d#", globals.dumpfile, epoch); if (NO_FORK) nofork = 1; else nofork = !forking || (globals.paranoid_dump == 2); /* Don't fork for dump/debug */ -#ifdef WIN32 +#if defined(WIN32) || !defined(HAVE_FORK) nofork = 1; #endif split = 0; @@ -625,7 +618,13 @@ fork_and_dump(int forking) if (!nofork) { #ifndef WIN32 +#ifdef HAVE_FORK child = fork(); +#else + /* Never actually reached, since nofork is set to 1 if HAVE_FORK is + * not defined. */ + child = -1; +#endif if (child < 0) { /* Oops, fork failed. Let's do a nofork dump */ do_log(LT_ERR, 0, 0, @@ -640,17 +639,10 @@ fork_and_dump(int forking) } } else if (child > 0) { forked_dump_pid = child; + lower_priority_by(child, 8); chunk_fork_parent(); } else { chunk_fork_child(); -#ifdef HAS_SETPRIORITY - /* Lower the priority of the child to make parent more responsive */ -#ifdef HAS_GETPRIORITY - setpriority(PRIO_PROCESS, child, getpriority(PRIO_PROCESS, child) + 4); -#else /* HAS_GETPRIORITY */ - setpriority(PRIO_PROCESS, child, 8); -#endif /* HAS_GETPRIORITY */ -#endif /* HAS_SETPRIORITY */ } #endif /* WIN32 */ } else { @@ -677,7 +669,7 @@ fork_and_dump(int forking) _exit(status); /* !!! */ } else { reserve_fd(); - if (!status && DUMP_NOFORK_COMPLETE && *DUMP_NOFORK_COMPLETE) + if (status && DUMP_NOFORK_COMPLETE && *DUMP_NOFORK_COMPLETE) flag_broadcast(0, 0, "%s", DUMP_NOFORK_COMPLETE); } } @@ -765,6 +757,12 @@ init_game_config(const char *conf) void (*handler)(); int a; + pid_t mypid = -1; + + /* initialize random number generator */ + initialize_mt(); + + init_queue(); global_eval_context.process_command_port = 0; global_eval_context.break_called = 0; @@ -782,8 +780,8 @@ init_game_config(const char *conf) global_eval_context.renv[a][0] = '\0'; global_eval_context.rnxt[a] = NULL; } - clear_namedregs(&global_eval_context.namedregs); - clear_namedregs(&global_eval_context.namedregsnxt); + init_namedregs(&global_eval_context.namedregs); + init_namedregs(&global_eval_context.namedregsnxt); /* set MUSH start time */ globals.start_time = time((time_t *) 0); @@ -794,8 +792,7 @@ init_game_config(const char *conf) init_flagspaces(); init_flag_table("FLAG"); init_func_hashtab(); - init_math_hashtab(); - init_tag_hashtab(); + init_ansi_codes(); init_aname_table(); init_atr_name_tree(); init_locks(); @@ -818,9 +815,13 @@ init_game_config(const char *conf) /* Initialize the attribute chunk storage */ chunk_init(); +#ifdef HAVE_GETPID + mypid = getpid(); +#endif + do_rawlog(LT_ERR, "CobraMUSH v%s [%s]", VERSION, VBRANCH); do_rawlog(LT_ERR, T("MUSH restarted, PID %d, at %s"), - (int) getpid(), show_time(globals.start_time, 0)); + (int) mypid, show_time(globals.start_time, 0)); } /** Post-db-load configuration. @@ -838,8 +839,6 @@ init_game_postdb(const char *conf) /* access file stuff */ read_access_file(); - /* initialize random number generator */ - initialize_mt(); /* set up signal handlers for the timer */ init_timer(); init_postconvert(); @@ -850,6 +849,7 @@ init_game_postdb(const char *conf) attr_init_postconfig(); /* Load further restrictions from config file */ config_file_startup(conf, 1); + validate_config(); #ifdef RPMODE_SYS init_rplogs(); #endif @@ -1008,7 +1008,8 @@ init_game_dbs(void) db_close(f); panicdb = 0; } - } + } else /* Close the panicdb file handle */ + db_close(f); if (!panicdb) { f = db_open(mailfile); @@ -1077,7 +1078,7 @@ do_readcache(dbref player) #define cmd_match(x) atr_comm_match(x, player, '$', ':', cptr, 0, NULL, NULL, &errdb) #define MAYBE_ADD_ERRDB(errdb) \ do { \ - if (GoodObject(errdb)) { \ + if (GoodObject(errdb) && errdblist) { \ if ((errdbtail - errdblist) >= errdbsize) \ errdb_grow(); \ if ((errdbtail - errdblist) < errdbsize) { \ @@ -1175,7 +1176,9 @@ process_command(dbref player, char *command, dbref cause, dbref realcause, int dbref check_loc; if (!errdblist) - errdblist = mush_malloc(errdbsize * sizeof(dbref), "errdblist"); + if (!(errdblist = mush_calloc(errdbsize, sizeof(dbref), "errdblist"))) + mush_panic("Unable to allocate memory in process_command()!"); + errdbtail = errdblist; errdb = NOTHING; depth = 0; @@ -1352,11 +1355,14 @@ process_command(dbref player, char *command, dbref cause, dbref realcause, int /* command has been executed. Free up memory. */ done: - ; + mush_free(errdblist, "errdblist"); + errdblist = errdbtail = NULL; + errdbsize = ERRDB_INITIAL_SIZE; } -COMMAND (cmd_with) { +COMMAND(cmd_with) +{ dbref what; char *cptr = arg_right; dbref errdb; @@ -1432,7 +1438,7 @@ check_alias(const char *command, const char *list) * \retval 1 a match was made. * \retval 0 no match was made. */ -int +static int list_check(dbref thing, dbref player, char type, char end, char *str, int just_match) { @@ -2007,7 +2013,7 @@ linux_uptime(dbref player __attribute__ ((__unused__))) FILE *fp; char line[128]; /* Overkill */ char *nl; - Pid_t pid; + pid_t pid; int psize; #ifdef HAS_GETRUSAGE struct rusage usage; @@ -2135,7 +2141,8 @@ win32_uptime(dbref player __attribute__ ((__unused__))) static void unix_uptime(dbref player __attribute__ ((__unused__))) { -#ifdef HAS_UPTIME +#ifndef WIN32 +#ifdef HAVE_UPTIME FILE *fp; char c; int i; @@ -2143,18 +2150,16 @@ unix_uptime(dbref player __attribute__ ((__unused__))) #ifdef HAS_GETRUSAGE struct rusage usage; #endif -#ifndef WIN32 char tbuf1[BUFFER_LEN]; -#endif - Pid_t pid; + pid_t pid; int psize; -#ifdef HAS_UPTIME +#ifdef HAVE_UPTIME fp = #ifdef __LCC__ (FILE *) #endif - popen(UPTIME_PATH, "r"); + popen(UPTIME, "r"); /* just in case the system is screwy */ if (fp == NULL) { @@ -2169,7 +2174,7 @@ unix_uptime(dbref player __attribute__ ((__unused__))) pclose(fp); notify(player, tbuf1); -#endif /* HAS_UPTIME */ +#endif /* HAVE_UPTIME */ /* do process stats */ (void) getcwd(tbuf1, BUFFER_LEN); @@ -2202,7 +2207,7 @@ unix_uptime(dbref player __attribute__ ((__unused__))) usage.ru_nvcsw, usage.ru_nivcsw); notify_format(player, "Signals: %10ld", usage.ru_nsignals); #endif /* HAS_GETRUSAGE */ - +#endif } #endif @@ -2211,13 +2216,15 @@ unix_uptime(dbref player __attribute__ ((__unused__))) * This command implements @uptime. * \endverbatim * \param player the enactor. - * \param mortal if 1, show mortal display, even if player is privileged. */ + void -do_uptime(dbref player, int mortal) +do_uptime(dbref player) { char tbuf1[BUFFER_LEN]; struct tm *when; + long days; + ldiv_t hours, mins, secs; when = localtime(&globals.first_start_time); strftime(tbuf1, sizeof tbuf1, T(" Up since %a %b %d %X %Z %Y"), when); @@ -2243,51 +2250,48 @@ do_uptime(dbref player, int mortal) /* calculate times until various events */ when = localtime(&options.dump_counter); strftime(tbuf1, sizeof tbuf1, "%X", when); + secs = ldiv((long) difftime(options.dump_counter, mudtime), 60); notify_format(player, T ("Time until next database save: %ld minutes %ld seconds, at %s"), - ((long) difftime(options.dump_counter, mudtime)) / 60, - ((long) difftime(options.dump_counter, mudtime)) % 60, tbuf1); + secs.quot, secs.rem, tbuf1); - when = localtime(&options.dbck_counter); + when = localtime(&options.dbck_counter); strftime(tbuf1, sizeof tbuf1, "%X", when); + secs = ldiv((long) difftime(options.dbck_counter, mudtime), 60); notify_format(player, T (" Time until next dbck check: %ld minutes %ld seconds, at %s."), - ((long) difftime(options.dbck_counter, mudtime)) / 60, - ((long) difftime(options.dbck_counter, mudtime)) % 60, tbuf1); + secs.quot, secs.rem, tbuf1); when = localtime(&options.purge_counter); strftime(tbuf1, sizeof tbuf1, "%X", when); + secs = ldiv((long) difftime(options.purge_counter, mudtime), 60); notify_format(player, T (" Time until next purge: %ld minutes %ld seconds, at %s."), - ((long) difftime(options.purge_counter, mudtime)) / 60, - ((long) difftime(options.purge_counter, mudtime)) % 60, tbuf1); + secs.quot, secs.rem, tbuf1); if (options.warn_interval) { when = localtime(&options.warn_counter); strftime(tbuf1, sizeof tbuf1, "%X", when); + secs = ldiv((long) difftime(options.warn_counter, mudtime), 60); notify_format(player, T (" Time until next @warnings: %ld minutes %ld seconds, at %s."), - ((long) difftime(options.warn_counter, mudtime)) / 60, - ((long) difftime(options.warn_counter, mudtime)) % 60, tbuf1); + secs.quot, secs.rem, tbuf1); } - - notify_format(player, - T - ("CobraMUSH Uptime: %ld days %ld hours %ld minutes %ld seconds"), - ((long) difftime(mudtime, globals.first_start_time)) / 86400, - ((long) difftime(mudtime, globals.first_start_time) % 86400) / - 3600, - (((long) difftime(mudtime, globals.first_start_time) % 86400) % - 3600) / 60, - (((long) difftime(mudtime, globals.first_start_time) % 86400) % - 3600) % 60); + + secs = ldiv((long) difftime(mudtime, globals.first_start_time), 86400); + days = secs.quot; + hours = ldiv(secs.rem, 3600); + mins = ldiv(hours.rem, 60); + + notify_format(player, T("CobraMUSH Uptime: %ld days %ld hours %ld minutes %ld seconds"), + days, hours.quot, mins.quot, mins.rem); /* Mortals, go no further! */ - if (!Site(player) || mortal) + if (!Site(player)) return; #if defined(linux) linux_uptime(player); @@ -2422,24 +2426,29 @@ do_list(dbref player, char *arg, int lc) do_list_flags(player, "", lc); else if (string_prefix("powers", arg)) do_list_powers(player, ""); + else if (string_prefix("locks", arg)) + do_list_locks(player, NULL, lc, T("Locks")); + else if (string_prefix("allocations", arg)) + do_list_allocations(player); else notify(player, T("I don't understand what you want to @list.")); } extern HASHTAB htab_function; extern HASHTAB htab_user_function; -extern HASHTAB htab_math; -extern HASHTAB htab_tag; extern HASHTAB htab_player_list; extern HASHTAB htab_reserved_aliases; extern HASHTAB help_files; extern HASHTAB htab_objdata; +extern HASHTAB htab_objdata_keys; +extern HASHTAB htab_locks; extern StrTree atr_names; extern StrTree lock_names; extern StrTree object_names; extern PTAB ptab_command; extern PTAB ptab_attrib; extern PTAB ptab_flag; +extern intmap *queue_map, *descs_by_fd; /** Reports stats on various in-memory data structures. * \param player the enactor. @@ -2451,12 +2460,13 @@ do_list_memstats(dbref player) hash_stats_header(player); hash_stats(player, &htab_function, "Functions"); hash_stats(player, &htab_user_function, "@Functions"); - hash_stats(player, &htab_math, "Math funs"); - hash_stats(player, &htab_tag, "HTML tags"); hash_stats(player, &htab_player_list, "Players"); hash_stats(player, &htab_reserved_aliases, "Aliases"); hash_stats(player, &help_files, "HelpFiles"); hash_stats(player, &htab_objdata, "ObjData"); + hash_stats(player, &htab_objdata_keys, "ObjDataKeys"); + hash_stats(player, &htab_locks, "@locks"); + hash_stats(player, &local_options, "ConfigOpts"); notify(player, "Prefix Trees:"); ptab_stats_header(player); ptab_stats(player, &ptab_attrib, "AttrPerms"); @@ -2467,6 +2477,11 @@ do_list_memstats(dbref player) st_stats(player, &atr_names, "AttrNames"); st_stats(player, &object_names, "ObjNames"); st_stats(player, &lock_names, "LockNames"); + notify(player, "Integer Maps:"); + im_stats_header(player); + im_stats(player, queue_map, "Queue IDs"); + im_stats(player, descs_by_fd, "Connections"); + #if (COMPRESSION_TYPE >= 3) && defined(COMP_STATS) if (Site(player)) { long items, used, total_comp, total_uncomp; @@ -2500,8 +2515,6 @@ do_list_memstats(dbref player) } #endif - if (Site(player)) - list_mem_check(player); } static char * @@ -2538,9 +2551,14 @@ fail_commands(dbref player) static void errdb_grow(void) { + dbref *newerrdb; if (errdbsize >= 50) return; /* That's it, no more, forget it */ - errdbsize++; - errdblist = realloc(errdblist, errdbsize * sizeof(dbref)); - errdbtail = errdblist + errdbsize - 1; + newerrdb = mush_realloc(errdblist, (errdbsize + 1) * sizeof(dbref), + "errdblist"); + if (newerrdb) { + errdblist = newerrdb; + errdbtail = errdblist + errdbsize; + errdbsize += 1; + } } diff --git a/src/help.c b/src/help.c index 102e949..841f302 100644 --- a/src/help.c +++ b/src/help.c @@ -10,6 +10,7 @@ #include #include #include +#include #include "conf.h" #include "externs.h" #include "boolexp.h" @@ -32,9 +33,10 @@ static int help_init = 0; static void do_new_spitfile(dbref player, char *arg1, help_file *help_dat); static const char *string_spitfile(help_file *help_dat, char *arg1); static help_indx *help_find_entry(help_file *help_dat, const char *the_topic); -static const char *list_matching_entries(char *pattern, help_file *help_dat, - const char *sep); -static const char *normalize_entry(help_file *help_dat, char *arg1); +static char **list_matching_entries(const char *pattern, + help_file *help_dat, int *len); +static void free_entry_list(char **); +static const char *normalize_entry(help_file *help_dat, const char *arg1); static void help_build_index(help_file *h, int restricted); @@ -52,10 +54,8 @@ unsigned top_topics = 0; /**< Maximum number of topics loaded */ static void write_topic(long int p); -#define TRUE 1 /**< A true value */ -#define FALSE 0 /**< A false value */ - -COMMAND (cmd_helpcmd) { +COMMAND(cmd_helpcmd) +{ help_file *h; h = hashfind(cmd->name, &help_files); @@ -70,20 +70,38 @@ COMMAND (cmd_helpcmd) { return; } - if (wildcard(arg_left)) - notify_format(player, T("Here are the entries which match '%s':\n%s"), - arg_left, list_matching_entries(arg_left, h, ", ")); - else + if (wildcard(arg_left)) { + int len = 0; + char **entries; + + entries = list_matching_entries(arg_left, h, &len); + if (len == 0) + notify_format(player, T("No entries matching '%s' were found."), + arg_left); + else if (len == 1) + do_new_spitfile(player, *entries, h); + else { + char buff[BUFFER_LEN]; + char *bp; + + bp = buff; + arr2list(entries, len, buff, &bp, ", "); + *bp = '\0'; + notify_format(player, T("Here are the entries which match '%s':\n%s"), + arg_left, buff); + } + free_entry_list(entries); + } else do_new_spitfile(player, arg_left, h); } -/** Initialize the helpfile hashtable, which contains the names of the +/** Initialize the helpfile hashtable, which contains the names of thes * help files. */ void init_help_files(void) { - hash_init(&help_files, 8, sizeof(help_file), NULL); + hashinit(&help_files, 8); help_init = 1; } @@ -141,10 +159,11 @@ help_reindex(dbref player) { help_file *curr; - for (curr = (help_file *) hash_firstentry(&help_files); - curr; curr = (help_file *) hash_nextentry(&help_files)) { + for (curr = hash_firstentry(&help_files); + curr; curr = hash_nextentry(&help_files)) { if (curr->indx) { - mush_free((Malloc_t) curr->indx, "help_index"); + mush_free(curr->indx, "help_index"); + curr->indx = NULL; curr->entries = 0; } help_build_index(curr, curr->admin); @@ -212,13 +231,13 @@ do_new_spitfile(dbref player, char *arg1, help_file *help_dat) /* ANSI topics */ if (ShowAnsi(player)) { char ansi_topic[LINE_SIZE + 10]; - sprintf(ansi_topic, "%s%s%s", ANSI_HILITE, the_topic, ANSI_NORMAL); + sprintf(ansi_topic, "%s%s%s", ANSI_HILITE, the_topic, ANSI_END); notify(player, ansi_topic); } else notify(player, the_topic); if (SUPPORT_PUEBLO) - notify_noenter(player, tprintf("%cSAMP%c", TAG_START, TAG_END)); + notify_noenter(player, open_tag("SAMP")); for (n = 0; n < BUFFER_LEN; n++) { if (fgets(line, LINE_SIZE, fp) == NULL) break; @@ -234,7 +253,7 @@ do_new_spitfile(dbref player, char *arg1, help_file *help_dat) } } if (SUPPORT_PUEBLO) - notify_format(player, "%c/SAMP%c", TAG_START, TAG_END); + notify(player, close_tag("SAMP")); fclose(fp); if (n >= BUFFER_LEN) notify_format(player, T("%s output truncated."), help_dat->command); @@ -244,10 +263,10 @@ do_new_spitfile(dbref player, char *arg1, help_file *help_dat) static help_indx * help_find_entry(help_file *help_dat, const char *the_topic) { - size_t n; help_indx *entry = NULL; if (help_dat->entries < 10) { /* Just do a linear search for small files */ + size_t n; for (n = 0; n < help_dat->entries; n++) { if (string_prefix(help_dat->indx[n].topic, the_topic)) { entry = &help_dat->indx[n]; @@ -260,7 +279,7 @@ help_find_entry(help_file *help_dat, const char *the_topic) int right = help_dat->entries - 1; while (1) { - n = (left + right) / 2; + int n = (left + right) / 2; if (left > right) break; @@ -334,8 +353,9 @@ static void help_build_index(help_file *h, int restricted) { long bigpos, pos = 0; - int in_topic; - int i, n, lineno, ntopics; + bool in_topic; + int i, lineno, ntopics; + size_t n; char *s, *topic; char the_topic[TOPIC_NAME_LEN + 1]; char line[LINE_SIZE + 1]; @@ -346,7 +366,8 @@ help_build_index(help_file *h, int restricted) if (!h || !h->file) return; if ((rfp = fopen(h->file, FOPEN_READ)) == NULL) { - do_rawlog(LT_ERR, T("Can't open %s for reading"), h->file); + do_rawlog(LT_ERR, T("Can't open %s for reading: %s"), h->file, + strerror(errno)); return; } @@ -394,7 +415,7 @@ help_build_index(help_file *h, int restricted) if (ntopics > 1) { write_topic(pos); } - in_topic = TRUE; + in_topic = true; } /* parse out the topic */ /* Get the beginning of the topic string */ @@ -421,7 +442,7 @@ help_build_index(help_file *h, int restricted) if (in_topic) { pos = bigpos; } - in_topic = FALSE; + in_topic = false; } bigpos = ftell(rfp); } @@ -453,11 +474,14 @@ FUNCTION(fun_textfile) } if (wildcard(args[1])) { - const char *entries = list_matching_entries(args[1], h, ", "); - if (*entries) - safe_str(entries, buff, bp); - else + char **entries; + int len = 0; + entries = list_matching_entries(args[1], h, &len); + if (len == 0) safe_str(T("No matching help topics."), buff, bp); + else + arr2list(entries, len, buff, bp, ", "); + free_entry_list(entries); } else safe_str(string_spitfile(h, args[1]), buff, bp); } @@ -466,6 +490,8 @@ FUNCTION(fun_textfile) FUNCTION(fun_textentries) { help_file *h; + char **entries; + int len = 0; const char *sep = " "; h = hashfind(strupper(args[0]), &help_files); @@ -479,11 +505,16 @@ FUNCTION(fun_textentries) } if (nargs > 2) sep = args[2]; - safe_str(list_matching_entries(args[1], h, sep), buff, bp); + + entries = list_matching_entries(args[1], h, &len); + if (entries) { + arr2list(entries, len, buff, bp, sep); + free_entry_list(entries); + } } static const char * -normalize_entry(help_file *help_dat, char *arg1) +normalize_entry(help_file *help_dat, const char *arg1) { static char the_topic[LINE_SIZE + 2]; @@ -491,13 +522,10 @@ normalize_entry(help_file *help_dat, char *arg1) arg1 = (char *) "help"; else if (*arg1 == '&') return T("#-1 INVALID ENTRY"); - if (strlen(arg1) > LINE_SIZE) - *(arg1 + LINE_SIZE) = '\0'; - if (help_dat->admin) - sprintf(the_topic, "&%s", arg1); + snprintf(the_topic, LINE_SIZE, "&%s", arg1); else - strcpy(the_topic, arg1); + mush_strncpy(the_topic, arg1, LINE_SIZE); return the_topic; } @@ -542,16 +570,12 @@ string_spitfile(help_file *help_dat, char *arg1) } /** Return a string with all help entries that match a pattern */ -static const char * -list_matching_entries(char *pattern, help_file *help_dat, const char *sep) +static char ** +list_matching_entries(const char *pattern, help_file *help_dat, int *len) { - static char buff[BUFFER_LEN]; + char **buff; int offset; - char *bp; size_t n; - int len; - - bp = buff; if (help_dat->admin) offset = 1; /* To skip the leading & */ @@ -563,31 +587,37 @@ list_matching_entries(char *pattern, help_file *help_dat, const char *sep) char the_topic[LINE_SIZE + 2]; help_indx *entry = NULL; strcpy(the_topic, normalize_entry(help_dat, pattern)); - if (!help_dat->indx || help_dat->entries == 0) - return T("#-1 NO INDEX FOR FILE"); + if (!help_dat->indx || help_dat->entries == 0) { + *len = 0; + return NULL; + } entry = help_find_entry(help_dat, the_topic); - if (!entry) - return (char *) ""; - return (char *) (entry->topic + offset); + if (!entry) { + *len = 0; + return NULL; + } else { + *len = 1; + buff = mush_malloc(sizeof(char **), "help.search"); + *buff = entry->topic + offset; + return buff; + } } - bp = buff; - - if (sep) - len = strlen(sep); + buff = mush_calloc(help_dat->entries, sizeof(char *), "help.search"); + *len = 0; for (n = 0; n < help_dat->entries; n++) if (quick_wild(pattern, help_dat->indx[n].topic + offset)) { - safe_str(help_dat->indx[n].topic + offset, buff, &bp); - if (sep) - safe_strl(sep, len, buff, &bp); + buff[*len] = help_dat->indx[n].topic + offset; + *len += 1; } - if (bp > buff) - *(bp - len) = '\0'; - else { - *bp = '\0'; - } - return buff; } + +static void +free_entry_list(char **entries) +{ + if (entries) + mush_free(entries, "help.search"); +} diff --git a/src/htab.c b/src/htab.c index 6cafc02..231ef69 100644 --- a/src/htab.c +++ b/src/htab.c @@ -2,15 +2,52 @@ * \file htab.c * * \brief Hashtable routines. - * This code is largely ripped out of TinyMUSH 2.2.5, with tweaks - * to make it Penn-compatible by Trivian. * + * The hash tables here implement open addressing using cuckoo hashing + * to resolve collisions. This gives an O(1) worse-case performance + * (As well as best, of course), compared to the worst-case O(N) of + * chained or linear probing tables. + * + * A lookup will require at most X hash functions and string + * comparisions. The old tables had, with data used by Penn, 1 hash + * function and up to 6 or 7 comparisions in the worst case. Best case + * for both is 1 hash and 1 comparision. Cuckoo hashing comes out + * ahead when most lookups are successful; true for normal usage in + * Penn. * + * Insertions are more expensive, but that's okay because we do a lot + * fewer of those. + * + * For details on the technique, see + * http://citeseer.ist.psu.edu/pagh01cuckoo.html + * + * Essentially: Use X hash functions (3 for us), and when inserting, + * try them in order looking for an empty bucket. If none are found, + * use one of the full buckets for the new entry, and bump the old one + * to another one of its possible buckets. Repeat the bumping some + * bounded number of times (Otherwise the possiblity of an infinite + * loop arises), and if no empty buckets are found, try rehashing the + * entire table with a new set of hash functions. If those are + * exhausted, only then grow the table. + * + * Possible to-do: Switch the string tree implementation from using + * red-black trees to these tables. Talek choose binary trees over + * hash tables when writing strtree.c because of the better worst-case + * behavior, which was a good decision at the time. However, O(1) is + * better than O(log N). + * + * At the moment, though, insertions can be fairly costly. The growth + * factor should be able to be specified -- large for cases where fast + * inserts are important, small for cases where we want to save save. */ #include "config.h" #include "copyrite.h" #include +#include +#ifdef HAVE_STDINT_H +#include +#endif #include "conf.h" #include "externs.h" @@ -18,19 +55,7 @@ #include "mymalloc.h" #include "confmagic.h" -HASHENT *hash_new(HASHTAB *htab, const char *key); -static int hash_val(register const char *k, int mask); - -/* --------------------------------------------------------------------------- - * hash_val: Compute hash value of a string for a hash table. - */ -/*#define NEW_HASH_FUN /**/ -#ifdef NEW_HASH_FUN - -/* This hash function adapted from http://burtleburtle.net/bob/hash/evahash.html */ - -typedef unsigned long int u4; /**< unsigned 4-byte type */ -typedef unsigned char u1; /**< unsigned 1-byte type */ +/* The Jenkins hash: http://burtleburtle.net/bob/hash/evahash.html */ /* The mixing step */ #define mix(a,b,c) \ @@ -47,23 +72,29 @@ typedef unsigned char u1; /**< unsigned 1-byte type */ } /* The whole new hash function */ -static int -hash_val(register const char *k, int mask) +static uint32_t +jenkins_hash(const char *k, int len) { - register u4 a, b, c; /* the internal state */ - u4 len, length; /* how many key bytes still need mixing */ - static u4 initval = 5432; /* the previous hash, or an arbitrary value */ + uint32_t a, b, c; /* the internal state */ + uint32_t length; /* how many key bytes still need mixing */ + static uint32_t initval = 5432; /* the previous hash, or an arbitrary value */ /* Set up the internal state */ - length = len = strlen(k); + length = len; a = b = 0x9e3779b9; /* the golden ratio; an arbitrary value */ c = initval; /* variable initialization of internal state */ /*---------------------------------------- handle most of the key */ while (len >= 12) { - a = a + (k[0] + ((u4) k[1] << 8) + ((u4) k[2] << 16) + ((u4) k[3] << 24)); - b = b + (k[4] + ((u4) k[5] << 8) + ((u4) k[6] << 16) + ((u4) k[7] << 24)); - c = c + (k[8] + ((u4) k[9] << 8) + ((u4) k[10] << 16) + ((u4) k[11] << 24)); + a = + a + (k[0] + ((uint32_t) k[1] << 8) + ((uint32_t) k[2] << 16) + + ((uint32_t) k[3] << 24)); + b = + b + (k[4] + ((uint32_t) k[5] << 8) + ((uint32_t) k[6] << 16) + + ((uint32_t) k[7] << 24)); + c = + c + (k[8] + ((uint32_t) k[9] << 8) + ((uint32_t) k[10] << 16) + + ((uint32_t) k[11] << 24)); mix(a, b, c); k = k + 12; len = len - 12; @@ -73,79 +104,285 @@ hash_val(register const char *k, int mask) c = c + length; switch (len) { /* all the case statements fall through */ case 11: - c = c + ((u4) k[10] << 24); + c = c + ((uint32_t) k[10] << 24); case 10: - c = c + ((u4) k[9] << 16); + c = c + ((uint32_t) k[9] << 16); case 9: - c = c + ((u4) k[8] << 8); + c = c + ((uint32_t) k[8] << 8); /* the first byte of c is reserved for the length */ case 8: - b = b + ((u4) k[7] << 24); + b = b + ((uint32_t) k[7] << 24); case 7: - b = b + ((u4) k[6] << 16); + b = b + ((uint32_t) k[6] << 16); case 6: - b = b + ((u4) k[5] << 8); + b = b + ((uint32_t) k[5] << 8); case 5: b = b + k[4]; case 4: - a = a + ((u4) k[3] << 24); + a = a + ((uint32_t) k[3] << 24); case 3: - a = a + ((u4) k[2] << 16); + a = a + ((uint32_t) k[2] << 16); case 2: - a = a + ((u4) k[1] << 8); + a = a + ((uint32_t) k[1] << 8); case 1: a = a + k[0]; /* case 0: nothing left to add */ } mix(a, b, c); /*-------------------------------------------- report the result */ - return c & mask; + return c; } -#else /* NEW_HASH_FUN */ -/** Compute a hash value for mask-style hashing. - * Given a null key, return 0. Otherwise, add up the numeric value - * of all the characters and return the sum modulo the size of the - * hash table. - * \param key key to hash. - * \param hashmask hash table size to use as modulus. - * \return hash value. - */ -int -hash_val(const char *key, int hashmask) +/* The Hsieh hash function. See + http://www.azillionmonkeys.com/qed/hash.html */ + +#undef get16bits +#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \ + || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__) +#define get16bits(d) (*((const uint16_t *) (d))) +#endif + +#if !defined (get16bits) +#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8)\ + +(uint32_t)(((const uint8_t *)(d))[0]) ) +#endif + +static uint32_t +hsieh_hash(const char *data, int len) { - int hash = 0; - const char *sp; + uint32_t hash, tmp; + int rem; - if (!key || !*key) + hash = len; + + if (len <= 0 || data == NULL) return 0; - for (sp = key; *sp; sp++) - hash = (hash << 5) + hash + *sp; - return (hash & hashmask); + + rem = len & 3; + len >>= 2; + + /* Main loop */ + for (; len > 0; len--) { + hash += get16bits(data); + tmp = (get16bits(data + 2) << 11) ^ hash; + hash = (hash << 16) ^ tmp; + data += 2 * sizeof(uint16_t); + hash += hash >> 11; + } + + /* Handle end cases */ + switch (rem) { + case 3: + hash += get16bits(data); + hash ^= hash << 16; + hash ^= data[sizeof(uint16_t)] << 18; + hash += hash >> 11; + break; + case 2: + hash += get16bits(data); + hash ^= hash << 11; + hash += hash >> 17; + break; + case 1: + hash += *data; + hash ^= hash << 10; + hash += hash >> 1; + } + + /* Force "avalanching" of final 127 bits */ + hash ^= hash << 3; + hash += hash >> 5; + hash ^= hash << 4; + hash += hash >> 17; + hash ^= hash << 25; + hash += hash >> 6; + + return hash; } -#endif /* NEW_HASH_FUN */ -/* ---------------------------------------------------------------------- - * hash_getmask: Get hash mask for mask-style hashing. +/* FNV hash: http://isthe.com/chongo/tech/comp/fnv/ */ +/* + * fnv_32_str - perform a 32 bit Fowler/Noll/Vo hash on a string + * + * input: + * str - string to hash + * hval - previous hash value or 0 if first call + * + * returns: + * 32 bit hash as a static hash type + * + * NOTE: To use the 32 bit FNV-0 historic hash, use FNV0_32_INIT as the hval + * argument on the first call to either fnv_32_buf() or fnv_32_str(). + * + * NOTE: To use the recommended 32 bit FNV-1 hash, use FNV1_32_INIT as the hval + * argument on the first call to either fnv_32_buf() or fnv_32_str(). + * + * Modified by Raevnos: Takes length arg, no hval arg, and does array-style + * iteration of the string. */ +#define FNV_32_PRIME ((Fnv32_t)0x01000193) +static inline uint32_t +fnv_hash(const char *str, int len) +{ + const unsigned char *s = (const unsigned char *) str; + int n; + uint32_t hval = 0; + + /* + * FNV-1 hash each octet in the buffer + */ + for (n = 0; n < len; n++) { + + /* multiply by the 32 bit FNV magic prime mod 2^32 */ +#if defined(NO_FNV_GCC_OPTIMIZATION) + hval *= FNV_32_PRIME; +#else + hval += + (hval << 1) + (hval << 4) + (hval << 7) + (hval << 8) + (hval << 24); +#endif + + /* xor the bottom with the current octet */ + hval ^= (uint32_t) s[n]; + } -/** Get the hash mask for mask-style hashing. - * Given the data size, return closest power-of-two less than that size. - * \param size data size. - * \return hash mask. - */ -int -hash_getmask(int *size) + /* return our new hash value */ + return hval; +} + +/* Silly old Penn hash function. */ +static uint32_t +penn_hash(const char *key, int len) { - int tsize; + uint32_t hash = 0; + int n; - if (!size || !*size) + if (!key || !*key || len == 0) return 0; + for (n = 0; n < len; n++) + hash = (hash << 5) + hash + key[n]; + return hash; +} + +typedef uint32_t(*hash_func) (const char *, int); + +hash_func hash_functions[] = { + hsieh_hash, + fnv_hash, + jenkins_hash, + penn_hash, + hsieh_hash, + fnv_hash, + penn_hash, + jenkins_hash +}; + +enum { NHASH_TRIES = 3, NHASH_MOD = 8 }; - for (tsize = 1; tsize < *size; tsize = tsize << 1) ; - *size = tsize; - return tsize - 1; +/* Return the next prime number after its arg */ +static int +next_prime_after(int val) +{ + /* Most of the first thousand primes */ + static int primes[] = { + 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, + 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, + 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, + 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, + 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, + 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, + 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, + 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, + 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, + 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, + 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997, 1009, 1013, 1019, + 1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063, 1069, 1087, 1091, 1093, + 1097, 1103, 1109, 1117, 1123, 1129, 1151, 1153, 1163, 1171, 1181, 1187, + 1193, 1201, 1213, 1217, 1223, 1229, 1231, 1237, 1249, 1259, 1277, 1279, + 1283, 1289, 1291, 1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, + 1373, 1381, 1399, 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451, 1453, + 1459, 1471, 1481, 1483, 1487, 1489, 1493, 1499, 1511, 1523, 1531, 1543, + 1549, 1553, 1559, 1567, 1571, 1579, 1583, 1597, 1601, 1607, 1609, 1613, + 1619, 1621, 1627, 1637, 1657, 1663, 1667, 1669, 1693, 1697, 1699, 1709, + 1721, 1723, 1733, 1741, 1747, 1753, 1759, 1777, 1783, 1787, 1789, 1801, + 1811, 1823, 1831, 1847, 1861, 1867, 1871, 1873, 1877, 1879, 1889, 1901, + 1907, 1913, 1931, 1933, 1949, 1951, 1973, 1979, 1987, 1993, 1997, 1999, + 2003, 2011, 2017, 2027, 2029, 2039, 2053, 2063, 2069, 2081, 2083, 2087, + 2089, 2099, 2111, 2113, 2129, 2131, 2137, 2141, 2143, 2153, 2161, 2179, + 2203, 2207, 2213, 2221, 2237, 2239, 2243, 2251, 2267, 2269, 2273, 2281, + 2287, 2293, 2297, 2309, 2311, 2333, 2339, 2341, 2347, 2351, 2357, 2371, + 2377, 2381, 2383, 2389, 2393, 2399, 2411, 2417, 2423, 2437, 2441, 2447, + 2459, 2467, 2473, 2477, 2503, 2521, 2531, 2539, 2543, 2549, 2551, 2557, + 2579, 2591, 2593, 2609, 2617, 2621, 2633, 2647, 2657, 2659, 2663, 2671, + 2677, 2683, 2687, 2689, 2693, 2699, 2707, 2711, 2713, 2719, 2729, 2731, + 2741, 2749, 2753, 2767, 2777, 2789, 2791, 2797, 2801, 2803, 2819, 2833, + 2837, 2843, 2851, 2857, 2861, 2879, 2887, 2897, 2903, 2909, 2917, 2927, + 2939, 2953, 2957, 2963, 2969, 2971, 2999, 3001, 3011, 3019, 3023, 3037, + 3041, 3049, 3061, 3067, 3079, 3083, 3089, 3109, 3119, 3121, 3137, 3163, + 3167, 3169, 3181, 3187, 3191, 3203, 3209, 3217, 3221, 3229, 3251, 3253, + 3257, 3259, 3271, 3299, 3301, 3307, 3313, 3319, 3323, 3329, 3331, 3343, + 3347, 3359, 3361, 3371, 3373, 3389, 3391, 3407, 3413, 3433, 3449, 3457, + 3461, 3463, 3467, 3469, 3491, 3499, 3511, 3517, 3527, 3529, 3533, 3539, + 3541, 3547, 3557, 3559, 3571, 3581, 3583, 3593, 3607, 3613, 3617, 3623, + 3631, 3637, 3643, 3659, 3671, 3673, 3677, 3691, 3697, 3701, 3709, 3719, + 3727, 3733, 3739, 3761, 3767, 3769, 3779, 3793, 3797, 3803, 3821, 3823, + 3833, 3847, 3851, 3853, 3863, 3877, 3881, 3889, 3907, 3911, 3917, 3919, + 3923, 3929, 3931, 3943, 3947, 3967, 3989, 4001, 4003, 4007, 4013, 4019, + 4021, 4027, 4049, 4051, 4057, 4073, 4079, 4091, 4093, 4099, 4111, 4127, + 4129, 4133, 4139, 4153, 4157, 4159, 4177, 4201, 4211, 4217, 4219, 4229, + 4231, 4241, 4243, 4253, 4259, 4261, 4271, 4273, 4283, 4289, 4297, 4327, + 4337, 4339, 4349, 4357, 4363, 4373, 4391, 4397, 4409, 4421, 4423, 4441, + 4447, 4451, 4457, 4463, 4481, 4483, 4493, 4507, 4513, 4517, 4519, 4523, + 4547, 4549, 4561, 4567, 4583, 4591, 4597, 4603, 4621, 4637, 4639, 4643, + 4649, 4651, 4657, 4663, 4673, 4679, 4691, 4703, 4721, 4723, 4729, 4733, + 4751, 4759, 4783, 4787, 4789, 4793, 4799, 4801, 4813, 4817, 4831, 4861, + 4871, 4877, 4889, 4903, 4909, 4919, 4931, 4933, 4937, 4943, 4951, 4957, + 4967, 4969, 4973, 4987, 4993, 4999, 5003, 5009, 5011, 5021, 5023, 5039, + 5051, 5059, 5077, 5081, 5087, 5099, 5101, 5107, 5113, 5119, 5147, 5153, + 5167, 5171, 5179, 5189, 5197, 5209, 5227, 5231, 5233, 5237, 5261, 5273, + 5279, 5281, 5297, 5303, 5309, 5323, 5333, 5347, 5351, 5381, 5387, 5393, + 5399, 5407, 5413, 5417, 5419, 5431, 5437, 5441, 5443, 5449, 5471, 5477, + 5479, 5483, 5501, 5503, 5507, 5519, 5521, 5527, 5531, 5557, 5563, 5569, + 5573, 5581, 5591, 5623, 5639, 5641, 5647, 5651, 5653, 5657, 5659, 5669, + 5683, 5689, 5693, 5701, 5711, 5717, 5737, 5741, 5743, 5749, 5779, 5783, + 5791, 5801, 5807, 5813, 5821, 5827, 5839, 5843, 5849, 5851, 5857, 5861, + 5867, 5869, 5879, 5881, 5897, 5903, 5923, 5927, 5939, 5953, 5981, 5987, + 6007, 6011, 6029, 6037, 6043, 6047, 6053, 6067, 6073, 6079, 6089, 6091, + 6101, 6113, 6121, 6131, 6133, 6143, 6151, 6163, 6173, 6197, 6199, 6203, + 6211, 6217, 6221, 6229, 6247, 6257, 6263, 6269, 6271, 6277, 6287, 6299, + 6301, 6311, 6317, 6323, 6329, 6337, 6343, 6353, 6359, 6361, 6367, 6373, + 6379, 6389, 6397, 6421, 6427, 6449, 6451, 6469, 6473, 6481, 6491, 6521, + 6529, 6547, 6551, 6553, 6563, 6569, 6571, 6577, 6581, 6599, 6607, 6619, + 6637, 6653, 6659, 6661, 6673, 6679, 6689, 6691, 6701, 6703, 6709, 6719, + 6733, 6737, 6761, 6763, 6779, 6781, 6791, 6793, 6803, 6823, 6827, 6829, + 6833, 6841, 6857, 6863, 6869, 6871, 6883, 6899, 6907, 6911, 6917, 6947, + 6949, 6959, 6961, 6967, 6971, 6977, 6983, 6991, 6997, 7001, 7013, 7019, + 7027, 7039, 7043, 7057, 7069, 7079, 7103, 7109, 7121, 7127, 7129, 7151, + 7159, 7177, 7187, 7193, 7207, 7211, 7213, 7219, 7229, 7237, 7243, 7247, + 7253, 7283, 7297, 7307, 7309, 7321, 7331, 7333, 7349, 7351, 7369, 7393, + 7411, 7417, 7433, 7451, 7457, 7459, 7477, 7481, 7487, 7489, 7499, 7507, + 7517, 7523, 7529, 7537, 7541, 7547, 7549, 7559, 7561, 7573, 7577, 7583, + 7589, 7591, 7603, 7607, 7621, 7639, 7643, 7649, 7669, 7673, 7681, 7687, + 7691, 7699, 7703, 7717, 7723, 7727, 7741, 7753, 7757, 7759, 7789, 7793, + 7817, 7823, 7829, 7841, 7853, 7867, 7873, 7877, 7879, 7883, 7901, 7907, + 7919, -1 + }; + int n; + int nprimes = sizeof primes / sizeof(int); + + /* Find the first prime greater than val */ + primes[nprimes - 1] = val + 1; + n = 0; + while (primes[n] < val) + n += 1; + + n += 1; + if (n == nprimes) + /* Semi-gracefully deal with numbers larger than the table has. + Should never happen, though. */ + return val + 1; + else + return primes[n]; } /** Initialize a hashtable. @@ -154,19 +391,14 @@ hash_getmask(int *size) * \param data_size size of an individual datum to store in the table. */ void -hash_init(HASHTAB *htab, int size, int data_size, void (*free_data) (void *)) +hash_init(HASHTAB *htab, int size, void (*free_data) (void *)) { - int i; - - htab->mask = get_hashmask(&size); - htab->hashsize = size; - htab->entries = 0; - htab->buckets = mush_malloc(size * sizeof(HASHENT *), "hash_buckets"); - for (i = 0; i < size; i++) - htab->buckets[i] = NULL; - - htab->entry_size = data_size; + size = next_prime_after(size); + htab->last_index = -1; htab->free_data = free_data; + htab->hashsize = size; + htab->hashfunc_offset = 0; + htab->buckets = mush_calloc(size, sizeof(struct hash_bucket), "hash.buckets"); } /** Return a hashtable entry given a key. @@ -177,153 +409,156 @@ hash_init(HASHTAB *htab, int size, int data_size, void (*free_data) (void *)) HASHENT * hash_find(HASHTAB *htab, const char *key) { - int hval, cmp; - HASHENT *hptr; + int len, n; - if (!htab->buckets) + if (!htab->entries) return NULL; - hval = hash_val(key, htab->mask); - for (hptr = htab->buckets[hval]; hptr != NULL; hptr = hptr->next) { - cmp = strcmp(key, hptr->key); - if (cmp == 0) { - return hptr; - } else if (cmp < 0) - break; + len = strlen(key); + + for (n = 0; n < NHASH_TRIES; n++) { + hash_func hash; + int hval, hashindex = (n + htab->hashfunc_offset) % NHASH_MOD; + hash = hash_functions[hashindex]; + hval = hash(key, len) % htab->hashsize; + + if (htab->buckets[hval].key && strcmp(htab->buckets[hval].key, key) == 0) + return htab->buckets + hval; } + return NULL; } -/** Return the value stored in a hash entry. - * \param entry pointer to a hash table entry. - * \return generic pointer to the stored value. - */ -void * -hash_value(HASHENT *entry) -{ - if (entry) - return entry->data; - else - return NULL; -} +enum { BUMP_LIMIT = 10 }; -/** Return the key stored in a hash entry. - * \param entry pointer to a hash table entry. - * \return pointer to the stored key. - */ -char * -hash_key(HASHENT *entry) +/** Do cuckoo hash cycling */ +static bool +hash_insert(HASHTAB *htab, const char *key, void *data) { - if (entry) - return entry->key; - else - return NULL; -} + int loop = 0, n; + struct hash_bucket bump; -/** Resize a hash table. - * \param htab pointer to hashtable. - * \param size new size. - */ -void -hash_resize(HASHTAB *htab, int size) -{ - int i; - HASHENT **oldarr; - HASHENT **newarr; - HASHENT *hent, *nent, *curr, *old; - int hval; - int osize; - int mask; - - /* We don't want hashes outside these limits */ - if ((size < (1 << 4)) || (size > (1 << 20))) - return; + bump.key = key; + bump.data = data; - /* Save the old data we need */ - osize = htab->hashsize; - oldarr = htab->buckets; + while (loop < BUMP_LIMIT) { + int hval, keylen; + struct hash_bucket temp; - mask = htab->mask = get_hashmask(&size); + keylen = strlen(bump.key); - if (size == htab->hashsize) - return; + /* See if bump has any empty choices and use it */ + for (n = 0; n < NHASH_TRIES; n++) { + hash_func hash; + int hashindex = (n + htab->hashfunc_offset) % NHASH_MOD; - htab->hashsize = size; - newarr = - (HASHENT **) mush_malloc(size * sizeof(struct hashentry *), "hash_buckets"); - htab->buckets = newarr; - for (i = 0; i < size; i++) - newarr[i] = NULL; - - for (i = 0; i < osize; i++) { - hent = oldarr[i]; - while (hent) { - nent = hent->next; - hval = hash_val(hent->key, mask); - for (curr = newarr[hval], old = NULL; curr; old = curr, curr = curr->next) { - if (strcmp(curr->key, hent->key) > 0) - break; - } - if (old) { - old->next = hent; - hent->next = curr; - } else { - hent->next = newarr[hval]; - newarr[hval] = hent; + hash = hash_functions[hashindex]; + hval = hash(bump.key, keylen) % htab->hashsize; + if (htab->buckets[hval].key == NULL) { + htab->buckets[hval] = bump; + return true; } - hent = nent; } + + /* None. Use a random func and bump the existing element */ + n = htab->hashfunc_offset + get_random_long(0, NHASH_TRIES - 1); + n %= NHASH_MOD; + hval = (hash_functions[n]) (bump.key, keylen) % htab->hashsize; + temp = htab->buckets[hval]; + htab->buckets[hval] = bump; + bump = temp; + loop += 1; } - mush_free(oldarr, "hash_buckets"); - return; + /* At this point, we've bumped BUMP_LIMIT times. Probably in a + loop. Find the first empty bucket, add the last bumped to, and + return failure. */ + for (n = 0; n < htab->hashsize; n++) + if (htab->buckets[n].key == NULL) { + htab->buckets[n] = bump; + return false; + } + + /* Never reached. */ + return false; } -HASHENT * -hash_new(HASHTAB *htab, const char *key) + +static int resize_calls = 0, first_offset = -1; + +/** Resize a hash table. + * \param htab pointer to hashtable. + * \param primesize new size. + * \param hashindex Index of first hash function to use + */ +static bool +real_hash_resize(HASHTAB *htab, int newsize, int hashfunc_offset) { - int hval; - size_t keylen; - HASHENT *hptr, *curr, *old; - - hptr = hash_find(htab, key); - if (hptr) - return hptr; - - if (htab->entries > (htab->hashsize * HTAB_UPSCALE)) - hash_resize(htab, htab->hashsize << 1); - - hval = hash_val(key, htab->mask); - htab->entries++; - keylen = strlen(key) + 1; - hptr = (HASHENT *) mush_malloc(HASHENT_SIZE + keylen, "hash_entry"); - memcpy(hptr->key, key, keylen); - hptr->data = NULL; - - if (!htab->buckets[hval] || strcmp(key, htab->buckets[hval]->key) < 0) { - hptr->next = htab->buckets[hval]; - htab->buckets[hval] = hptr; - return hptr; + HASHENT *oldarr; + int oldsize, oldoffset, i; + + /* Massive overkill here */ + if (resize_calls > 150) { + fputs("Ooops. Too many attempts to resize a hash table.\n", stderr); + return false; + } + + /* If all possible hash function combos have been exhausted, + grow the array */ + if (hashfunc_offset == first_offset) { + int newersize = next_prime_after(floor(newsize * 1.15)); + first_offset = -1; + return real_hash_resize(htab, newersize, hashfunc_offset); } - /* Insert in sorted order. There's always at least one item in - the chain already at this point. */ - old = htab->buckets[hval]; - for (curr = old->next; curr; old = curr, curr = curr->next) { - /* Comparison will never be 0 because hash_add checks to see - if the entry is already present. */ - if (strcmp(key, curr->key) < 0) { /* Insert before curr */ - old->next = hptr; - hptr->next = curr; - return hptr; + resize_calls += 1; + + /* Save the old data we need */ + oldsize = htab->hashsize; + oldoffset = htab->hashfunc_offset; + oldarr = htab->buckets; + + htab->buckets = + mush_calloc(newsize, sizeof(struct hash_bucket), "hash.buckets"); + htab->hashsize = newsize; + htab->hashfunc_offset = hashfunc_offset; + for (i = 0; i < oldsize; i++) { + + if (oldarr[i].key) { + + if (!hash_insert(htab, oldarr[i].key, oldarr[i].data)) { + /* Couldn't fit an element in. Try with different hash functions. */ + mush_free(htab->buckets, "hash.buckets"); + htab->buckets = oldarr; + htab->hashsize = oldsize; + htab->hashfunc_offset = oldoffset; + if (first_offset == -1) + first_offset = hashfunc_offset; + return + real_hash_resize(htab, newsize, (hashfunc_offset + 1) % NHASH_MOD); + } } } - /* If we get here, we reached the end of the chain */ - old->next = hptr; - hptr->next = NULL; + mush_free(oldarr, "hash.buckets"); + return true; +} - return hptr; +/** Resize a hash table. + * \param htab pointer to hashtable. + * \param size new size. + */ +bool +hash_resize(HASHTAB *htab, int size) +{ + if (htab) { + htab->last_index = -1; + first_offset = -1; + resize_calls = 0; + return real_hash_resize(htab, next_prime_after(size), + htab->hashfunc_offset); + } else + return false; } /** Add an entry to a hash table. @@ -331,27 +566,31 @@ hash_new(HASHTAB *htab, const char *key) * \param key key string to store data under. * \param hashdata void pointer to data to be stored. * \param extra_size unused. - * \retval -1 failure. - * \retval 0 success. + * \retval false failure. + * \retval true success. */ -int -hash_add(HASHTAB *htab, const char *key, void *hashdata, - int extra_size __attribute__ ((__unused__))) +bool +hash_add(HASHTAB *htab, const char *key, void *hashdata) { - HASHENT *hptr; + const char *keycopy; - if (hash_find(htab, key) != NULL) { - return -1; - } + if (hash_find(htab, key) != NULL) + return false; - hptr = hash_new(htab, key); + htab->entries += 1; - if (!hptr) - return -1; + keycopy = mush_strdup(key, "hash.key"); - hptr->data = hashdata; - /* hptr->extra_size = extra_size; */ - return 0; + if (!hash_insert(htab, keycopy, hashdata)) { + first_offset = -1; + resize_calls = 0; + if (!real_hash_resize(htab, htab->hashsize, + (htab->hashfunc_offset + 1) % NHASH_MOD)) { + htab->entries -= 1; + return false; + } + } + return true; } /** Delete an entry in a hash table. @@ -361,28 +600,14 @@ hash_add(HASHTAB *htab, const char *key, void *hashdata, void hash_delete(HASHTAB *htab, HASHENT *entry) { - int hval; - HASHENT *hptr, *last; - if (!entry) return; - hval = hash_val(entry->key, htab->mask); - last = NULL; - for (hptr = htab->buckets[hval]; hptr; last = hptr, hptr = hptr->next) { - if (entry == hptr) { - if (last == NULL) - htab->buckets[hval] = hptr->next; - else - last->next = hptr->next; - mush_free(hptr, "hash_entry"); - htab->entries--; - return; - } - } - - if (htab->entries < (htab->hashsize * HTAB_DOWNSCALE)) - hash_resize(htab, htab->hashsize >> 1); + if (htab->free_data) + htab->free_data(entry->data); + mush_free((void *) entry->key, "hash.key"); + memset(entry, 0, sizeof *entry); + htab->entries -= 1; } /** Flush a hash table, freeing all entries. @@ -392,30 +617,26 @@ hash_delete(HASHTAB *htab, HASHENT *entry) void hash_flush(HASHTAB *htab, int size) { - HASHENT *hent, *thent; int i; + struct hash_bucket *resized; - if (htab->buckets) { + if (htab->entries) { for (i = 0; i < htab->hashsize; i++) { - hent = htab->buckets[i]; - while (hent != NULL) { - thent = hent; - hent = hent->next; - mush_free(thent, "hash_entry"); + if (htab->buckets[i].key) { + mush_free((void *) htab->buckets[i].key, "hash.key"); + if (htab->free_data) + htab->free_data(htab->buckets[i].data); } - htab->buckets[i] = NULL; } } - if (size == 0) { - mush_free(htab->buckets, "hash_buckets"); - htab->buckets = NULL; - } else if (size != htab->hashsize) { - if (htab->buckets) - mush_free(htab->buckets, "hash_buckets"); - hashinit(htab, size, htab->entry_size); - } else { - htab->entries = 0; + htab->entries = 0; + size = next_prime_after(size); + resized = mush_realloc(htab->buckets, size, "hash.buckets"); + if (resized) { + htab->buckets = resized; + htab->hashsize = size; } + memset(htab->buckets, 0, sizeof(struct hash_bucket) * htab->hashsize); } /** Return the first entry of a hash table. @@ -427,13 +648,12 @@ hash_flush(HASHTAB *htab, int size) void * hash_firstentry(HASHTAB *htab) { - int hval; + int n; - for (hval = 0; hval < htab->hashsize; hval++) - if (htab->buckets[hval]) { - htab->last_hval = hval; - htab->last_entry = htab->buckets[hval]; - return htab->buckets[hval]->data; + for (n = 0; n < htab->hashsize; n++) + if (htab->buckets[n].key) { + htab->last_index = n; + return htab->buckets[n].data; } return NULL; } @@ -444,16 +664,15 @@ hash_firstentry(HASHTAB *htab) * \param htab pointer to hash table. * \return first hash table key. */ -char * +const char * hash_firstentry_key(HASHTAB *htab) { - int hval; + int n; - for (hval = 0; hval < htab->hashsize; hval++) - if (htab->buckets[hval]) { - htab->last_hval = hval; - htab->last_entry = htab->buckets[hval]; - return htab->buckets[hval]->key; + for (n = 0; n < htab->hashsize; n++) + if (htab->buckets[n].key) { + htab->last_index = n; + return htab->buckets[n].key; } return NULL; } @@ -468,23 +687,13 @@ hash_firstentry_key(HASHTAB *htab) void * hash_nextentry(HASHTAB *htab) { - int hval; - HASHENT *hptr; - - hval = htab->last_hval; - hptr = htab->last_entry; - if (hptr->next) { - htab->last_entry = hptr->next; - return hptr->next->data; - } - hval++; - while (hval < htab->hashsize) { - if (htab->buckets[hval]) { - htab->last_hval = hval; - htab->last_entry = htab->buckets[hval]; - return htab->buckets[hval]->data; + int n = htab->last_index + 1; + while (n < htab->hashsize) { + if (htab->buckets[n].key) { + htab->last_index = n; + return htab->buckets[n].data; } - hval++; + n += 1; } return NULL; } @@ -496,26 +705,16 @@ hash_nextentry(HASHTAB *htab) * \param htab pointer to hash table. * \return next hash table key. */ -char * +const char * hash_nextentry_key(HASHTAB *htab) { - int hval; - HASHENT *hptr; - - hval = htab->last_hval; - hptr = htab->last_entry; - if (hptr->next) { - htab->last_entry = hptr->next; - return hptr->next->key; - } - hval++; - while (hval < htab->hashsize) { - if (htab->buckets[hval]) { - htab->last_hval = hval; - htab->last_entry = htab->buckets[hval]; - return htab->buckets[hval]->key; + int n = htab->last_index + 1; + while (n < htab->hashsize) { + if (htab->buckets[n].key) { + htab->last_index = n; + return htab->buckets[n].key; } - hval++; + n += 1; } return NULL; } @@ -527,7 +726,7 @@ void hash_stats_header(dbref player) { notify_format(player, - "Table Buckets Entries LChain ECh 1Ch 2Ch 3Ch 4+Ch AvgCh ~Memory"); + "Table Buckets Entries 1Lookup 2Lookup 3Lookup ~Memory"); } /** Display stats on a hashtable. @@ -538,41 +737,33 @@ hash_stats_header(dbref player) void hash_stats(dbref player, HASHTAB *htab, const char *hname) { - int longest = 0, n; - int lengths[5]; - double chainlens = 0.0; - double totchains = 0.0; - unsigned int bytes = 0; + int n; + size_t bytes; + unsigned int compares[3] = { 0, 0, 0 }; if (!htab || !hname) return; - for (n = 0; n < 5; n++) - lengths[n] = 0; - bytes += sizeof(HASHTAB); - if (htab->buckets) { - bytes += HASHENT_SIZE * htab->hashsize; - for (n = 0; n < htab->hashsize; n++) { - int chain = 0; - HASHENT *b; - if (htab->buckets[n]) { - for (b = htab->buckets[n]; b; b = b->next) { - chain++; - bytes += strlen(b->key) + 1 /* + b->extra_size */ ; - } - if (chain > longest) - longest = chain; + bytes = sizeof *htab; + bytes += sizeof(struct hash_bucket) * htab->hashsize; + + for (n = 0; n < htab->hashsize; n++) + if (htab->buckets[n].key) { + int i; + int len = strlen(htab->buckets[n].key); + bytes += len + 1; + for (i = 0; i < 3; i++) { + hash_func hash = + hash_functions[(i + htab->hashfunc_offset) % NHASH_MOD]; + if ((hash(htab->buckets[n].key, len) % htab->hashsize) == (uint32_t) n) { + compares[i] += 1; + break; + } } - lengths[(chain > 4) ? 4 : chain]++; - chainlens += chain; } - } - for (n = 1; n < 5; n++) - totchains += lengths[n]; notify_format(player, - "%-11s %7d %7d %6d %4d %4d %4d %4d %4d %6.3f %7u", hname, - htab->hashsize, htab->entries, longest, lengths[0], lengths[1], - lengths[2], lengths[3], lengths[4], - totchains > 0 ? chainlens / totchains : 0.0, bytes); + "%-11s %7d %7d %7u %7u %7u %7u", + hname, htab->hashsize, htab->entries, compares[0], compares[1], + compares[2], (unsigned int) bytes); } diff --git a/src/htmltab.c b/src/htmltab.c new file mode 100644 index 0000000..cedbc9a --- /dev/null +++ b/src/htmltab.c @@ -0,0 +1,256 @@ +/* ANSI-C code produced by gperf version 3.0.3p1 */ +/* Command-line: gperf --output-file htmltab.c htmltab.gperf */ +/* Computed positions: -k'1-2,$' */ + +#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \ + && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \ + && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \ + && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \ + && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \ + && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \ + && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \ + && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \ + && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \ + && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \ + && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \ + && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \ + && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \ + && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \ + && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \ + && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \ + && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \ + && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \ + && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \ + && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \ + && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \ + && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \ + && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126)) +/* The character set is not based on ISO-646. */ +#error "gperf generated tables don't work with this execution character set. Please report a bug to ." +#endif + +/* maximum key range = 127, duplicates = 0 */ + +#ifndef GPERF_DOWNCASE +#define GPERF_DOWNCASE 1 +static unsigned char gperf_downcase[256] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + 60, 61, 62, 63, 64, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, + 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, + 122, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, + 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, + 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, + 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, + 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, + 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, + 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, + 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, + 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, + 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, + 255 +}; +#endif + +#ifndef GPERF_CASE_MEMCMP +#define GPERF_CASE_MEMCMP 1 +static int +gperf_case_memcmp(register const char *s1, register const char *s2, + register unsigned int n) +{ + for (; n > 0;) { + unsigned char c1 = gperf_downcase[(unsigned char) *s1++]; + unsigned char c2 = gperf_downcase[(unsigned char) *s2++]; + if (c1 == c2) { + n--; + continue; + } + return (int) c1 - (int) c2; + } + return 0; +} +#endif + +#ifdef __GNUC__ +__inline +#ifdef __GNUC_STDC_INLINE__ + __attribute__ ((__gnu_inline__)) +#endif +#endif + static unsigned int + htmltag_hash(register const char *str, register unsigned int len) +{ + static const unsigned char asso_values[] = { + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 40, + 35, 30, 25, 20, 0, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 10, 5, 15, 5, 0, + 5, 10, 45, 25, 128, 0, 10, 25, 40, 45, + 15, 128, 15, 0, 0, 20, 60, 128, 128, 10, + 128, 128, 128, 128, 128, 128, 128, 10, 5, 15, + 5, 0, 5, 10, 45, 25, 128, 0, 10, 25, + 40, 45, 15, 128, 15, 0, 0, 20, 60, 128, + 128, 10, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128 + }; + register int hval = len; + + switch (hval) { + default: + hval += asso_values[(unsigned char) str[1]]; + /*FALLTHROUGH*/ case 1: + hval += asso_values[(unsigned char) str[0]]; + break; + } + return hval + asso_values[(unsigned char) str[len - 1]]; +} + +#ifdef __GNUC__ +__inline +#ifdef __GNUC_STDC_INLINE__ + __attribute__ ((__gnu_inline__)) +#endif +#endif + const char *is_allowed_tag(register const char *str, + register unsigned int len) +{ + enum { + TOTAL_KEYWORDS = 58, + MIN_WORD_LENGTH = 1, + MAX_WORD_LENGTH = 10, + MIN_HASH_VALUE = 1, + MAX_HASH_VALUE = 127 + }; + + static const unsigned char lengthtable[] = { + 0, 1, 2, 0, 0, 0, 6, 2, 0, 0, 5, 1, 2, 3, + 0, 5, 6, 2, 3, 0, 5, 1, 7, 0, 0, 10, 0, 2, + 3, 4, 0, 1, 2, 3, 4, 0, 6, 2, 3, 0, 5, 1, + 2, 3, 4, 0, 0, 2, 3, 4, 0, 1, 2, 3, 4, 5, + 0, 7, 0, 4, 0, 0, 2, 3, 4, 0, 0, 2, 3, 0, + 0, 0, 7, 3, 0, 0, 0, 2, 0, 0, 0, 0, 0, 8, + 0, 0, 0, 2, 3, 0, 0, 0, 2, 3, 0, 0, 0, 2, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 2 + }; + static const char *const wordlist[] = { + "", + "S", + "TT", + "", "", "", + "STRIKE", + "DT", + "", "", + "TFOOT", + "B", + "TD", + "KBD", + "", + "TABLE", + "STRONG", + "DD", + "DEL", + "", + "TBODY", + "A", + "ADDRESS", + "", "", + "BLOCKQUOTE", + "", + "DL", + "SUB", + "SAMP", + "", + "P", + "TR", + "PRE", + "ABBR", + "", + "CENTER", + "BR", + "SUP", + "", + "SMALL", + "U", + "UL", + "BIG", + "CITE", + "", "", + "H6", + "DIR", + "MENU", + "", + "I", + "EM", + "DFN", + "FONT", + "THEAD", + "", + "ACRONYM", + "", + "SPAN", + "", "", + "LI", + "IMG", + "CODE", + "", "", + "OL", + "INS", + "", "", "", + "CAPTION", + "COL", + "", "", "", + "HR", + "", "", "", "", "", + "COLGROUP", + "", "", "", + "H5", + "VAR", + "", "", "", + "TH", + "DIV", + "", "", "", + "H4", + "", "", "", "", "", "", "", "", "", + "H3", + "", "", "", "", "", "", "", "", "", + "H2", + "", "", "", "", "", "", "", "", "", + "H1" + }; + + if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH) { + register int key = htmltag_hash(str, len); + + if (key <= MAX_HASH_VALUE && key >= 0) + if (len == lengthtable[key]) { + register const char *s = wordlist[key]; + + if ((((unsigned char) *str ^ (unsigned char) *s) & ~32) == 0 + && !gperf_case_memcmp(str, s, len)) + return s; + } + } + return 0; +} + +#line 71 "htmltab.gperf" diff --git a/src/htmltab.gperf b/src/htmltab.gperf new file mode 100644 index 0000000..7f79610 --- /dev/null +++ b/src/htmltab.gperf @@ -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 +%% diff --git a/src/ident.c b/src/ident.c index 4ae8c99..cdab44a 100644 --- a/src/ident.c +++ b/src/ident.c @@ -11,9 +11,6 @@ */ #include "config.h" -#ifdef NeXT3 -#include -#endif #include #include @@ -26,9 +23,9 @@ #include #ifdef I_SYS_TIME #include +#ifdef TIME_WITH_SYS_TIME +#include #endif -#ifdef I_SYS_WAIT -#include #endif #include #ifndef WIN32 @@ -50,6 +47,9 @@ #endif #include #endif /* WIN32 */ +#ifdef HAVE_POLL_H +#include +#endif #ifdef I_UNISTD #include @@ -76,14 +76,14 @@ static ident_t *id_open(struct sockaddr *faddr, socklen_t flen, struct sockaddr *laddr, socklen_t llen, int *timeout); -static int id_query(ident_t * id, +static int id_query(ident_t *id, struct sockaddr *laddr, socklen_t llen, struct sockaddr *faddr, socklen_t flen, int *timeout); -static int id_close(ident_t * id); +static void id_close(ident_t *id); -static int id_parse(ident_t * id, int *timeout, IDENT **ident); +static int id_parse(ident_t *id, int *timeout, IDENT ** ident); static IDENT *ident_lookup(int fd, int *timeout); @@ -94,14 +94,14 @@ ident_lookup(int fd, int *timeout) union sockaddr_u localaddr, remoteaddr; socklen_t llen, rlen, len; - len = sizeof(remoteaddr); + len = sizeof remoteaddr; if (getpeername(fd, (struct sockaddr *) remoteaddr.data, &len) < 0) - return 0; + return NULL; llen = len; - len = sizeof(localaddr); + len = sizeof localaddr; if (getsockname(fd, (struct sockaddr *) localaddr.data, &len) < 0) - return 0; + return NULL; rlen = len; return ident_query(&localaddr.addr, llen, &remoteaddr.addr, rlen, timeout); @@ -116,12 +116,12 @@ ident_lookup(int fd, int *timeout) * \return ident responses in IDENT pointer, or NULL. */ IDENT * -ident_query(struct sockaddr *laddr, socklen_t llen, - struct sockaddr *raddr, socklen_t rlen, int *timeout) +ident_query(struct sockaddr * laddr, socklen_t llen, + struct sockaddr * raddr, socklen_t rlen, int *timeout) { int res; ident_t *id; - IDENT *ident = 0; + IDENT *ident = NULL; if (timeout && *timeout < 0) *timeout = 0; @@ -132,33 +132,24 @@ ident_query(struct sockaddr *laddr, socklen_t llen, #ifndef WIN32 errno = EINVAL; #endif -#ifdef DEBUG - fprintf(stderr, "id_open failed.\n"); -#endif - return 0; + return NULL; } res = id_query(id, raddr, rlen, laddr, llen, timeout); if (res < 0) { id_close(id); -#ifdef DEBUG - fprintf(stderr, "id_query failed.\n"); -#endif - return 0; + return NULL; } res = id_parse(id, timeout, &ident); - if (res != 1) { + if (res < 0) { id_close(id); -#ifdef DEBUG - fprintf(stderr, "id_parse failed.\n"); -#endif - return 0; + return NULL; } - id_close(id); + id_close(id); return ident; /* At last! */ } @@ -187,7 +178,7 @@ ident_id(int fd, int *timeout) * \param id pointer to IDENT structure to free. */ void -ident_free(IDENT *id) +ident_free(IDENT * id) { if (!id) return; @@ -205,8 +196,6 @@ ident_free(IDENT *id) ** Author: Peter Eriksson ** Fixes: Pär Emanuelsson */ - - static ident_t * id_open(struct sockaddr *faddr, socklen_t flen, struct sockaddr *laddr, socklen_t llen, int *timeout) @@ -214,81 +203,45 @@ id_open(struct sockaddr *faddr, socklen_t flen, ident_t *id; char host[NI_MAXHOST]; union sockaddr_u myinterface; - fd_set rs, ws, es; - struct timeval to; - int res; #ifndef WIN32 int tmperrno; #endif - if ((id = (ident_t *) malloc(sizeof(*id))) == 0) - return 0; + if ((id = malloc(sizeof *id)) == NULL) + return NULL; - memset(id, 0, sizeof(ident_t)); + memset(id, 0, sizeof *id); - if (getnameinfo(faddr, flen, host, sizeof(host), NULL, 0, + if (getnameinfo(faddr, flen, host, sizeof host, NULL, 0, NI_NUMERICHOST | NI_NUMERICSERV) != 0) { + penn_perror("id_open: getnameinfo"); free(id); - return 0; + return NULL; } /* Make sure we connect from the right interface. Changing the pointer directly doesn't seem to work. So... */ - memcpy(&myinterface, laddr, llen); + memcpy(&myinterface.data, laddr, llen); if (myinterface.addr.sa_family == AF_INET) ((struct sockaddr_in *) &myinterface.addr)->sin_port = 0; -#ifdef HAS_IPV6 /* Bleah, I wanted to avoid stuff like this */ +#ifdef HAVE_SOCKADDR_IN6 /* Bleah, I wanted to avoid stuff like this */ else if (myinterface.addr.sa_family == AF_INET6) ((struct sockaddr_in6 *) &myinterface.addr)->sin6_port = 0; #endif - id->fd = make_socket_conn(host, &myinterface.addr, llen, IDPORT, timeout); + id->fd = make_socket_conn(host, SOCK_STREAM, &myinterface.addr, llen, + IDPORT, timeout ? *timeout : 0); if (id->fd < 0) /* Couldn't connect to an ident server */ goto ERROR_BRANCH; - if (timeout) { - time_t now, after; - - FD_ZERO(&rs); - FD_ZERO(&ws); - FD_ZERO(&es); - FD_SET(id->fd, &rs); - FD_SET(id->fd, &ws); - FD_SET(id->fd, &es); - to.tv_sec = *timeout; - to.tv_usec = 0; - now = time(NULL); - if ((res = select(id->fd + 1, &rs, &ws, &es, &to)) < 0) { -#ifdef DEBUG - perror("libident: select"); -#endif - goto ERROR_BRANCH; - } - after = time(NULL); - *timeout -= after - now; - *timeout = *timeout < 0 ? 0 : *timeout; - - if (res == 0) { -#ifndef WIN32 - errno = ETIMEDOUT; -#endif - goto ERROR_BRANCH; - } - if (FD_ISSET(id->fd, &es)) - goto ERROR_BRANCH; - - if (!FD_ISSET(id->fd, &rs) && !FD_ISSET(id->fd, &ws)) - goto ERROR_BRANCH; - } return id; ERROR_BRANCH: #ifndef WIN32 tmperrno = errno; /* Save, so close() won't erase it */ #endif - closesocket(id->fd); - free(id); + id_close(id); #ifndef WIN32 errno = tmperrno; #endif @@ -300,15 +253,11 @@ ERROR_BRANCH: ** ** Author: Peter Eriksson */ -static int -id_close(ident_t * id) +static void +id_close(ident_t *id) { - int res; - - res = closesocket(id->fd); + closesocket(id->fd); free(id); - - return res; } @@ -319,49 +268,77 @@ id_close(ident_t * id) static int -id_query(ident_t * id, struct sockaddr *laddr, socklen_t llen, +id_query(ident_t *id, struct sockaddr *laddr, socklen_t llen, struct sockaddr *faddr, socklen_t flen, int *timeout) { int res; char buf[80]; - char port[NI_MAXSERV]; - fd_set ws; - struct timeval to; - - getnameinfo(laddr, llen, NULL, 0, port, sizeof(port), - NI_NUMERICHOST | NI_NUMERICSERV); - sprintf(buf, "%s , ", port); - getnameinfo(faddr, flen, NULL, 0, port, sizeof(port), - NI_NUMERICHOST | NI_NUMERICSERV); - strncat(buf, port, sizeof(buf)); - strncat(buf, "\r\n", sizeof(buf)); + char fport[NI_MAXSERV], lport[NI_MAXSERV]; + time_t now, after; + + if (getnameinfo(laddr, llen, NULL, 0, lport, sizeof lport, + NI_NUMERICHOST | NI_NUMERICSERV) < 0) { + penn_perror("id_query: getnameinfo"); + return -1; + } + if (getnameinfo(faddr, flen, NULL, 0, fport, sizeof fport, + NI_NUMERICHOST | NI_NUMERICSERV) < 0) { + penn_perror("id_query: getnameinfo2"); + return -1; + } + + snprintf(buf, sizeof buf, "%s , %s\r\n", lport, fport); + + time(&now); + if ((res = wait_for_connect(id->fd, timeout ? *timeout : -1)) <= 0) { + if (res < 0) + penn_perror("id_query: wait_for_connect"); + return -1; + } + time(&after); if (timeout) { - time_t now, after; - FD_ZERO(&ws); - FD_SET(id->fd, &ws); - to.tv_sec = *timeout; - to.tv_usec = 0; + *timeout -= (int) difftime(after, now); + *timeout = *timeout < 0 ? 0 : *timeout; + } + + make_blocking(id->fd); + + + while (1) { + if (timeout) { + struct timeval to; + socklen_t to_len; + + to.tv_sec = *timeout; + to.tv_usec = 0; + to_len = sizeof to; + if (setsockopt(id->fd, SOL_SOCKET, SO_SNDTIMEO, &to, to_len) < 0) { + penn_perror("id_query: setsockopt"); + return -1; + } + } + now = time(NULL); - if ((res = select(id->fd + 1, NULL, &ws, NULL, &to)) < 0) - return -1; + res = send(id->fd, buf, strlen(buf), 0); after = time(NULL); - *timeout -= after - now; - *timeout = *timeout < 0 ? 0 : *timeout; - if (res == 0) { -#ifndef WIN32 - errno = ETIMEDOUT; -#endif - return -1; + if (timeout) { + *timeout -= (int) difftime(after, now); + *timeout = *timeout < 0 ? 0 : *timeout; + if (*timeout == 0) + return -1; } + if (res < 0) { + if (errno == EINTR) + continue; + else if (errno != EAGAIN && errno != EWOULDBLOCK) + penn_perror("id_query: send"); + return -1; + } else + return res; } - /* Used to ignore SIGPIPE here, but we already ignore it anyways. */ - res = send(id->fd, buf, strlen(buf), 0); - - return res; } - /* id_parse.c Receive and parse a reply from an IDENT server ** ** Author: Peter Eriksson @@ -412,13 +389,11 @@ xstrtok(char *RESTRICT cp, const char *RESTRICT cs, char *RESTRICT dc) static int -id_parse(ident_t * id, int *timeout, IDENT **ident) +id_parse(ident_t *id, int *timeout, IDENT ** ident) { - char c, *cp, *tmp_charset; - fd_set rs; + char c, *cp, *tmp_charset = NULL; int res = 0, lp, fp; - size_t pos; - struct timeval to; + size_t pos, len; #ifndef WIN32 errno = 0; @@ -434,44 +409,53 @@ id_parse(ident_t * id, int *timeout, IDENT **ident) if (!*ident) return -1; - memset(*ident, 0, sizeof(IDENT)); + memset(*ident, 0, sizeof **ident); pos = strlen(id->buf); + len = IDBUFSIZE - pos; - if (timeout) { + do { time_t now, after; - FD_ZERO(&rs); - FD_SET(id->fd, &rs); - to.tv_sec = *timeout; - to.tv_usec = 0; + if (timeout) { + struct timeval to; + socklen_t to_len; + + to.tv_sec = *timeout; + to.tv_usec = 0; + to_len = sizeof to; + + if (setsockopt(id->fd, SOL_SOCKET, SO_RCVTIMEO, &to, to_len) < 0) { + penn_perror("id_parse: setsockopt"); + return -1; + } + } + now = time(NULL); - if ((res = select(id->fd + 1, &rs, NULL, NULL, &to)) < 0) - return -1; + res = recv(id->fd, id->buf + pos, len, 0); after = time(NULL); - *timeout -= after - now; - *timeout = *timeout < 0 ? 0 : *timeout; - if (res == 0) { -#ifndef WIN32 - errno = ETIMEDOUT; -#endif - return -1; + if (timeout) { + *timeout -= (int) difftime(after, now); + *timeout = *timeout < 0 ? 0 : *timeout; + if (*timeout == 0) + return -1; } - } - while (pos < sizeof(id->buf) && - (res = recv(id->fd, id->buf + pos, 1, 0)) == 1 && id->buf[pos] != '\n') - pos++; - if (res < 0) - return -1; - if (res == 0) { -#ifndef WIN32 - errno = ENOTCONN; -#endif - return -1; - } - if (id->buf[pos] != '\n') { + if (res < 0) { + if (errno == EAGAIN || errno == EWOULDBLOCK) + break; + else if (errno == EINTR) + continue; + else + return -1; + } + + len -= res; + pos += res; + } while (pos < len && res > 0 && id->buf[pos - 1] != '\n'); + + if (id->buf[pos - 1] != '\n') return 0; - } + id->buf[pos++] = '\0'; /* Get first field ( , ) */ diff --git a/src/info_master.c b/src/info_master.c new file mode 100644 index 0000000..5b4cadd --- /dev/null +++ b/src/info_master.c @@ -0,0 +1,395 @@ +/** + * \file info_master.c + * + * \brief mush-end functions for talking to info_slave + */ + +#include "copyrite.h" +#include "config.h" + +#ifdef I_SYS_TYPES +#include +#endif +#ifdef I_UNISTD +#include +#endif +#ifdef I_SYS_TIME +#include +#endif +#if !defined(I_SYS_TIME) || defined(TIME_WITH_SYS_TIME) +#include +#endif +#ifdef I_NETDB +#include +#endif +#ifdef I_SYS_SOCKET +#include +#endif + +#include +#include +#include +#include +#include + +#include "conf.h" +#include "externs.h" +#include "access.h" +#include "mysocket.h" +#include "ident.h" +#include "lookup.h" +#include "log.h" +#include "wait.h" + + +#ifdef INFO_SLAVE + +#ifdef WIN32 +#error "info_slave will not work on Windows." +#endif + +#ifndef HAVE_SOCKETPAIR +#error "no supported communication options for talking with info_slave are available." +#endif + +static bool make_info_slave(void); + +static fd_set info_pending; /**< Keep track of fds pending a slave lookup */ +static int pending_max = 0; +int info_slave = -1; +pid_t info_slave_pid = -1; /**< Process id of the info_slave process */ +enum is_state info_slave_state = INFO_SLAVE_DOWN; /**< State of the info_slave process */ +time_t info_queue_time; /**< Time of last write to slave */ + +static int startup_attempts = 0; /**< How many times has info_slave been started? */ +static time_t startup_window; +#define MAX_ATTEMPTS 5 /**< Error out after this many startup attempts in 60 seconds */ + +bool info_slave_halted = false; + + /* From bsd.c */ +extern int maxd; +DESC *initializesock(int s, char *addr, char *ip, int use_ssl); + +/** Re-query lookups that have timed out */ +void +update_pending_info_slaves(void) +{ + time_t now; + int newsock; + + time(&now); + + if (info_slave_state == INFO_SLAVE_PENDING && now > info_queue_time + 30) { + /* rerun any pending queries that got lost */ + info_queue_time = now; + for (newsock = 0; newsock < pending_max; newsock++) + if (FD_ISSET(newsock, &info_pending)) + query_info_slave(newsock); + } +} + +void +init_info_slave(void) +{ + FD_ZERO(&info_pending); + make_info_slave(); +} + +bool +make_info_slave(void) +{ + int socks[2]; + pid_t child; + int n; + + if (info_slave_state != INFO_SLAVE_DOWN) { + if (info_slave_pid > 0) + kill_info_slave(); + info_slave_state = INFO_SLAVE_DOWN; + } + + if (startup_attempts == 0) + time(&startup_window); + + startup_attempts += 1; + + if (startup_attempts > MAX_ATTEMPTS) { + time_t now; + + time(&now); + if (difftime(now, startup_window) <= 60.0) { + /* Too many failed attempts to start info_slave in 1 minute */ + do_rawlog(LT_ERR, T("Disabling info_slave due to too many errors.")); + info_slave_halted = true; + return false; + } else { + /* Reset counter */ + startup_window = now; + startup_attempts = 0; + } + } +#ifndef AF_LOCAL + /* Use Posix.1g names. */ +#define AF_LOCAL AF_UNIX +#endif + +#ifdef HAVE_SOCKETPAIR + if (socketpair(AF_LOCAL, SOCK_DGRAM, 0, socks) < 0) { + penn_perror("creating slave datagram socketpair"); + return false; + } + if (socks[0] >= maxd) + maxd = socks[0] + 1; + if (socks[1] >= maxd) + maxd = socks[1] + 1; +#endif + + child = fork(); + if (child < 0) { + penn_perror("forking info slave"); +#ifdef HAVE_SOCKETPAIR + closesocket(socks[0]); + closesocket(socks[1]); +#endif + return false; + } else if (child > 0) { + info_slave_state = INFO_SLAVE_READY; + info_slave_pid = child; +#ifdef HAVE_SOCKETPAIR + info_slave = socks[0]; + closesocket(socks[1]); + do_rawlog(LT_ERR, + "Spawning info slave, communicating using socketpair, pid %d", + child); +#endif + make_nonblocking(info_slave); + } else { + int errfd = fileno(stderr); + int dupfd; + + /* Close unneeded fds and sockets: Everything but stderr and the + socket used to talk to the mush */ + for (n = 0; n < maxd; n++) { + if (n == errfd) + continue; +#ifdef HAVE_SOCKETPAIR + if (n == socks[1]) + continue; +#endif + close(n); + } + /* Reuse stdin and stdout for talking to the slave */ + dupfd = dup2(socks[1], 0); + if (dupfd < 0) { + penn_perror("dup2() of stdin in info_slave"); + exit(1); + } + + dupfd = dup2(socks[1], 1); + if (dupfd < 0) { + penn_perror("dup2() of stdout in info_slave"); + exit(1); + } + + close(socks[1]); + + execl("./info_slave", "info_slave", (char *) NULL); + penn_perror("execing info slave"); + exit(1); + } + + if (info_slave >= maxd) + maxd = info_slave + 1; + + lower_priority_by(info_slave, 4); + + for (n = 0; n < maxd; n++) + if (FD_ISSET(n, &info_pending)) + query_info_slave(n); + + return true; +} + +void +query_info_slave(int fd) +{ + struct request_dgram req; + struct hostname_info *hi; + char buf[BUFFER_LEN], *bp; + ssize_t slen; + + FD_SET(fd, &info_pending); + if (fd > pending_max) + pending_max = fd + 1; + + info_queue_time = time(NULL); + + if (info_slave_state == INFO_SLAVE_DOWN) { + if (!make_info_slave()) { + FD_CLR(fd, &info_pending); + closesocket(fd); /* Just drop the connection if the slave gets halted. + A subsequent reconnect will work. */ + } + return; + } + + + memset(&req, 0, sizeof req); + + req.rlen = MAXSOCKADDR; + if (getpeername(fd, (struct sockaddr *) req.remote.data, &req.rlen) < 0) { + penn_perror("socket peer vanished"); + shutdown(fd, 2); + closesocket(fd); + FD_CLR(fd, &info_pending); + return; + } + + /* Check for forbidden sites before bothering with ident */ + bp = buf; + hi = ip_convert(&req.remote.addr, req.rlen); + safe_str(hi ? hi->hostname : "Not found", buf, &bp); + *bp = '\0'; + if (Forbidden_Site(buf)) { + char port[NI_MAXSERV]; + if (getnameinfo(&req.remote.addr, req.rlen, NULL, 0, port, sizeof port, + NI_NUMERICHOST | NI_NUMERICSERV) != 0) + penn_perror("getting remote port number"); + else { + if (!Deny_Silent_Site(buf, AMBIGUOUS)) { + do_log(LT_CONN, 0, 0, T("[%d/%s] Refused connection (remote port %s)"), + fd, buf, port); + } + } + closesocket(fd); + FD_CLR(fd, &info_pending); + return; + } + + req.llen = MAXSOCKADDR; + if (getsockname(fd, (struct sockaddr *) req.local.data, &req.llen) < 0) { + penn_perror("socket self vanished"); + closesocket(fd); + FD_CLR(fd, &info_pending); + return; + } + + req.fd = fd; + req.use_dns = USE_DNS; + req.use_ident = USE_IDENT; + req.timeout = IDENT_TIMEOUT; + + slen = send(info_slave, &req, sizeof req, 0); + if (slen < 0) { + penn_perror("info slave query: write error"); + make_info_slave(); + return; + } else if (slen != (int) sizeof req) { + /* Shouldn't happen! */ + penn_perror("info slave query: partial packet"); + make_info_slave(); + return; + } + info_slave_state = INFO_SLAVE_PENDING; +} + +void +reap_info_slave(void) +{ + struct response_dgram resp; + ssize_t len; + char hostname[BUFFER_LEN], *hp; + int n, count; + + if (info_slave_state != INFO_SLAVE_PENDING) { + if (info_slave_state == INFO_SLAVE_DOWN) + make_info_slave(); + return; + } + + len = recv(info_slave, &resp, sizeof resp, 0); + if (len < 0 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)) + return; + else if (len < 0 || len != (int) sizeof resp) { + penn_perror("reading info_slave response"); + return; + } + + /* okay, now we have some info! */ + if (!FD_ISSET(resp.fd, &info_pending)) { + /* Duplicate or spoof. Ignore. */ + return; + } + + FD_CLR(resp.fd, &info_pending); + + /* See if we have any other pending queries and change state if not. */ + for (n = 0, count = 0; n < pending_max; n++) + if (FD_ISSET(n, &info_pending)) + count++; + + if (count == 0) { + info_slave_state = INFO_SLAVE_READY; + pending_max = 0; + } + + hp = hostname; + if (resp.ident[0]) { + safe_str(resp.ident, hostname, &hp); + safe_chr('@', hostname, &hp); + } + if (resp.hostname[0]) + safe_str(resp.hostname, hostname, &hp); + else + safe_str(resp.ipaddr, hostname, &hp); + *hp = '\0'; + + if (Forbidden_Site(resp.ipaddr) || Forbidden_Site(hostname)) { + if (!Deny_Silent_Site(resp.ipaddr, AMBIGUOUS) + || !Deny_Silent_Site(hostname, AMBIGUOUS)) { + do_log(LT_CONN, 0, 0, T("[%d/%s/%s] Refused connection."), resp.fd, + hostname, resp.ipaddr); + } + shutdown(resp.fd, 2); + closesocket(resp.fd); + return; + } + + do_log(LT_CONN, 0, 0, T("[%d/%s/%s] Connection opened."), resp.fd, + hostname, resp.ipaddr); + set_keepalive(resp.fd); + initializesock(resp.fd, hostname, resp.ipaddr, + (resp.connected_to == SSLPORT)); +} + +/** Kill the info_slave process, typically at shutdown. + */ +void +kill_info_slave(void) +{ + WAIT_TYPE my_stat; + pid_t pid; + + if (info_slave_state != INFO_SLAVE_DOWN) { + if (info_slave_pid > 0) { + do_rawlog(LT_ERR, "Terminating info_slave pid %d", info_slave_pid); + + block_a_signal(SIGCHLD); + + closesocket(info_slave); + kill(info_slave_pid, 15); + /* Have to wait long enough for the info_slave to actually + die. This will hopefully be enough time. */ + usleep(100); + + pid = mush_wait(info_slave_pid, &my_stat, WNOHANG); + info_slave_pid = -1; + unblock_a_signal(SIGCHLD); + } + info_slave_state = INFO_SLAVE_DOWN; + } +} + + +#endif /* INFO_SLAVE */ diff --git a/src/info_slave.c b/src/info_slave.c index 4ad2746..dfced0d 100644 --- a/src/info_slave.c +++ b/src/info_slave.c @@ -5,8 +5,11 @@ * * When running PennMUSH under Unix, a second process (info_slave) is * started and the server farms out DNS and ident lookups to the - * info_slave, and reads responses from the info_slave asynchronously. - * Communication between server and slave is by means of a local socket. + * info_slave, and reads responses from the info_slave + * asynchronously. Communication between server and slave is by means + * of datagrams on a connected UDP socket. + * + * info_slave takes one argument, the descriptor of the local socket. * */ #include "copyrite.h" @@ -21,213 +24,549 @@ #ifdef I_SYS_TYPES #include #endif +#ifdef I_SYS_TIME +#include +#endif #ifdef I_SYS_SOCKET #include #endif #ifdef I_NETINET_IN #include #endif +#ifdef I_NETDB #include +#endif #include #include #ifdef I_UNISTD #include #endif -#include +#ifdef HAVE_SYS_EVENT_H +#include +#endif +#ifdef HAVE_POLL_H +#include +#endif +#include +#include #include "conf.h" #include "externs.h" +#include "wait.h" #include "ident.h" #include "mysocket.h" -#include "confmagic.h" +#include "lookup.h" -/* Duplicate these, rather than trying to include strutil.o... */ -/** Arguments for functions that call APPEND_TO_BUF */ -#define APPEND_ARGS int len, blen, clen -/** Add string c to buffer buff of max length mlen */ -#define APPEND_TO_BUF(mlen) \ - /* Trivial cases */ \ - if (c[0] == '\0') \ - return 0; \ - /* The array is at least two characters long here */ \ - if (c[1] == '\0') \ - return safe_chr(c[0], buff, bp); \ - len = strlen(c); \ - blen = *bp - buff; \ - if (blen > (mlen)) \ - return len; \ - if ((len + blen) <= (mlen)) \ - clen = len; \ - else \ - clen = (mlen) - blen; \ - memcpy(*bp, c, clen); \ - *bp += clen; \ - return len - clen - -#ifdef SAFE_CHR_FUNCTION -int -safe_chr(char c, char *buf, char **bufp) -{ - /* adds a character to a string, being careful not to overflow buffer */ - - if ((*bufp - buf >= BUFFER_LEN - 1)) - return 1; +#include "confmagic.h" - *(*bufp)++ = c; - return 0; -} +#ifndef ENOTSUP +#define ENOTSUP EPERM #endif -int -safe_str(const char *c, char *buff, char **bp) -{ - /* copies a string into a buffer, making sure there's no overflow. */ - APPEND_ARGS; +void reap_children(void); +static void reaper(int); +int eventwait_init(void); +int eventwait_watch_fd_read(int); +int eventwait_watch_parent_exit(void); +int eventwait_watch_child_exit(void); +int eventwait(void); - if (!c || !*c) - return 0; +void fputerr(const char *); - APPEND_TO_BUF(BUFFER_LEN); -} +enum methods { METHOD_KQUEUE, METHOD_POLL, METHOD_SELECT }; -#undef APPEND_ARGS -#undef APPEND_TO_BUF +enum methods method; +/** How many simultaneous lookup processes can be running? If more + * attempts are made after this limit has been reached, the main + * slave processes does them sequentially until some of the subslaves + * exit. */ +enum { MAX_SLAVES = 5 }; +sig_atomic_t children = 0; +pid_t child_pids[MAX_SLAVES]; int -main(int argc, char *argv[]) +main(void) { - int mush; - int port; - int fd; - union sockaddr_u local, remote; - static char buf[BUFFER_LEN]; /* overkill */ - char *bp; - int len, size; - IDENT *ident_result; - char host[NI_MAXHOST]; - char lport[NI_MAXSERV]; - int use_ident, use_dns, timeout; - socklen_t llen, rlen; - struct iovec dat[3]; - - if (argc < 2) { - fprintf(stderr, "info_slave needs a port number!\n"); + struct request_dgram req; + struct response_dgram resp; + ssize_t len; + pid_t child, netmush = -2; + char localport[NI_MAXSERV]; + + if (new_process_group() < 0) + penn_perror("making new process group"); + +#ifdef HAVE_GETPPID + netmush = getppid(); +#endif + + if (eventwait_init() < 0) { + penn_perror("init_eventwait"); return EXIT_FAILURE; } - port = atoi(argv[1]); - use_ident = 1; - if (argc >= 3) { - /* The second argument is -1 if we don't want ident used. - * Anything else is the timeout. Default is 5 seconds. - */ - use_ident = atoi(argv[2]); - } else - use_ident = 5; - if (argc >= 4) { - /* The third argument is 1 to do DNS lookups, 0 to not. */ - use_dns = atoi(argv[3]); - } else - use_dns = 1; + if (eventwait_watch_fd_read(0) < 0) { + penn_perror("eventwait_add_fd"); + return EXIT_FAILURE; + } -#ifdef HAS_SOCKETPAIR - mush = port; /* We inherit open file descriptions and sockets from parent */ -#else - mush = make_socket_conn("127.0.0.1", NULL, 0, port, NULL); - if (mush == -1) { /* Couldn't connect */ - fprintf(stderr, "Couldn't connect to mush!\n"); + if (eventwait_watch_parent_exit() < 0) { + penn_perror("eventwait_add_fd"); + return EXIT_FAILURE; + } + + if (eventwait_watch_child_exit() < 0) { + penn_perror("eventwait_watch_child_exit"); return EXIT_FAILURE; } -#endif - /* yes, we are _blocking_ */ for (;;) { - /* grab a request */ - /* First, the address size. */ + /* grab a request datagram */ + int ev = eventwait(); - len = read(mush, &rlen, sizeof rlen); - if (len < (int) sizeof rlen) { - perror("info_slave reading remote size (Did the mush crash?)"); - return EXIT_FAILURE; - } - /* Now the first address and len of the second. */ - dat[0].iov_base = (char *) &remote.data; - dat[0].iov_len = rlen; - dat[1].iov_base = (char *) &llen; - dat[1].iov_len = sizeof llen; - size = rlen + sizeof llen; - len = readv(mush, dat, 2); - if (len < size) { - perror("info_slave reading remote sockaddr and local size"); - return EXIT_FAILURE; - } + if (ev == 0) + len = recv(0, &req, sizeof req, 0); + else if (ev == (int) netmush) { + /* Parent process exited. Exit too. */ + fputerr + ("info_slave: Parent mush process exited unexpectedly! Shutting down."); + return EXIT_SUCCESS; + } else if (ev < 0) { + /* Error? */ + if (errno != EINTR) { + penn_perror("eventwait"); + return EXIT_FAILURE; + } else + continue; + } else /* ev == 0 */ + continue; - /* Now the second address and fd. */ - dat[0].iov_base = (char *) &local.data; - dat[0].iov_len = llen; - dat[1].iov_base = (char *) &fd; - dat[1].iov_len = sizeof fd; - size = llen + sizeof fd; - len = readv(mush, dat, 2); - if (len < size) { - perror("info_slave reading local sockaddr and fd"); + if (len == -1 && errno == EINTR) + continue; + else if (len != (int) sizeof req) { + /* This shouldn't happen. */ + penn_perror("reading request datagram"); return EXIT_FAILURE; } - if (!fd) - /* MUSH aborted query part way through or only wrote a partial - * packet */ - continue; + if (children < MAX_SLAVES) { +#ifdef HAVE_FORK + child = fork(); + if (child < 0) { + /* Just do the lookup in the main info_slave */ + penn_perror("unable to fork; doing lookup in master slave"); + } else if (child > 0) { + /* Parent info_slave; wait for the next request. */ + children++; + continue; + } +#else + child = 1; +#endif + } else + child = 1; - bp = buf; - if (getnameinfo(&remote.addr, rlen, host, sizeof host, NULL, 0, - NI_NUMERICHOST | NI_NUMERICSERV) != 0) - safe_str("An error occured", buf, &bp); - else - safe_str(host, buf, &bp); - safe_chr('^', buf, &bp); - if (getnameinfo(&local.addr, llen, NULL, 0, lport, sizeof lport, + /* Now in the child info_slave or the master with a failed fork. Do a + * lookup and send back to the mush. + */ + + memset(&resp, 0, sizeof resp); + resp.fd = req.fd; + + if (getnameinfo(&req.remote.addr, req.rlen, resp.ipaddr, + sizeof resp.ipaddr, NULL, 0, NI_NUMERICHOST | NI_NUMERICSERV) != 0) - safe_str("An error occured", buf, &bp); + strcpy(resp.ipaddr, "An error occured"); + + if (getnameinfo(&req.local.addr, req.llen, NULL, 0, localport, + sizeof localport, NI_NUMERICHOST | NI_NUMERICSERV) != 0) + resp.connected_to = -1; else - safe_str(lport, buf, &bp); - safe_chr('^', buf, &bp); + resp.connected_to = strtol(localport, NULL, 10); - if (use_ident > 0) { - timeout = use_ident; + if (req.use_ident) { + IDENT *ident_result; + int timeout = req.timeout; ident_result = - ident_query(&local.addr, llen, &remote.addr, rlen, &timeout); + ident_query(&req.local.addr, req.llen, &req.remote.addr, req.rlen, + &timeout); if (ident_result && ident_result->identifier) { - safe_str(ident_result->identifier, buf, &bp); - safe_chr('@', buf, &bp); + strncpy(resp.ident, ident_result->identifier, sizeof resp.ident); + resp.ident[(sizeof resp.ident) - 1] = '\0'; } + if (ident_result) ident_free(ident_result); } - if (use_dns) { - if (getnameinfo(&remote.addr, rlen, host, sizeof host, NULL, 0, - NI_NUMERICSERV) != 0) { - safe_str("An error occured", buf, &bp); - } else { - safe_str(host, buf, &bp); - } + + if (req.use_dns) { + if (getnameinfo(&req.remote.addr, req.rlen, resp.hostname, + sizeof resp.hostname, NULL, 0, NI_NUMERICSERV) != 0) + strcpy(resp.hostname, resp.ipaddr); } else - safe_str(host, buf, &bp); - *bp = '\0'; - size = strlen(buf); - dat[0].iov_base = (char *) &fd; - dat[0].iov_len = sizeof fd; - dat[1].iov_base = (char *) &size; - dat[1].iov_len = sizeof size; - dat[2].iov_base = buf; - dat[2].iov_len = size; - len = writev(mush, dat, 3); - size = dat[0].iov_len + dat[1].iov_len + dat[2].iov_len; - if (len < size) { - perror("info_slave write packet"); + strcpy(resp.hostname, resp.ipaddr); + + len = send(1, &resp, sizeof resp, 0); + + /* Should never happen. */ + if (len != (int) sizeof resp) { + penn_perror("error writing packet"); return EXIT_FAILURE; } + + if (child == 0) + return EXIT_SUCCESS; } + return EXIT_SUCCESS; } + +void +reap_children(void) +{ + WAIT_TYPE status; + while (mush_wait(-1, &status, WNOHANG) > 0) + children--; +} + +static void +reaper(int signo) +{ + reap_children(); + reload_sig_handler(signo, reaper); +} + +/* Event watching code that tries to use various system-dependant ways + * of waiting for a variety of events. In particular, on BSD + * (Including OS X) systems, it uses kqueue()/kevent() to wait for a + * fd to be readable or a process to exit. On others, it uses poll(2) + * or select(2) with a timeout and periodic checking of getppid() to + * see if the parent netmush process still exists. + */ + +#define HAVE_SELECT + +#ifdef HAVE_SELECT +static fd_set readers; +static int maxd = 0; +static pid_t parent_pid = 0; +#endif + +#ifdef HAVE_KQUEUE +static int kqueue_id = -1; +#endif + +#ifdef HAVE_POLL +static struct pollfd *poll_fds = NULL; +static int pollfd_len = 0; +#endif + + +/** Initialize event loop + * \return 0 on success, -1 on failure + */ +int +eventwait_init(void) +{ +#ifdef HAVE_KQUEUE + kqueue_id = kqueue(); + lock_file(stderr); + fputs("info_slave: trying kqueue event loop... ", stderr); + if (kqueue_id < 0) { + unlock_file(stderr); + penn_perror("error"); + } else { + fputs("ok. Using kqueue!\n", stderr); + unlock_file(stderr); + } + + if (kqueue_id >= 0) { + method = METHOD_KQUEUE; + return 0; + } else +#endif +#ifdef HAVE_POLL + if (1) { + fputerr("info_slave: trying poll event loop... ok. Using poll."); + method = METHOD_POLL; + return 0; + } else +#endif +#ifdef HAVE_SELECT + if (1) { + fputerr("info_slave: trying select event loop... ok. Using select."); + FD_ZERO(&readers); + method = METHOD_SELECT; + return 0; + } else +#endif + { + fputerr("info_slave: No working event loop method!"); + errno = ENOTSUP; + return -1; + } +} + +/** Add a file descriptor to check for read events. + * Any number of descriptors can be added. + * \param fd the descriptor + * \return 0 on success, -1 on failure + */ +int +eventwait_watch_fd_read(int fd) +{ + switch (method) { +#ifdef HAVE_KQUEUE + case METHOD_KQUEUE:{ + struct kevent add; + struct timespec timeout; + + memset(&add, 0, sizeof add); + add.ident = fd; + add.flags = EV_ADD | EV_ENABLE; + add.filter = EVFILT_READ; + timeout.tv_sec = 0; + timeout.tv_nsec = 0; + + return kevent(kqueue_id, &add, 1, NULL, 0, &timeout); + } +#endif +#ifdef HAVE_POLL + case METHOD_POLL: + poll_fds = realloc(poll_fds, sizeof(struct pollfd) * (pollfd_len + 1)); + poll_fds[pollfd_len].fd = fd; + poll_fds[pollfd_len].events = POLLIN; + pollfd_len += 1; + return 0; +#endif +#ifdef HAVE_SELECT + case METHOD_SELECT: + FD_SET(fd, &readers); + if (fd >= maxd) + maxd = fd + 1; + return 0; +#endif + default: + return -1; + } +} + +/** Monitor parent process for exiting. + * \return 0 on success, -1 on error. + */ +int +eventwait_watch_parent_exit(void) +{ + pid_t parent; + + +#ifdef HAVE_GETPPID + parent = getppid(); +#else + errno = ENOTSUP; + return -1; +#endif + + switch (method) { +#ifdef HAVE_KQUEUE + case METHOD_KQUEUE:{ + struct kevent add; + struct timespec timeout; + + memset(&add, 0, sizeof(add)); + add.ident = parent; + add.flags = EV_ADD | EV_ENABLE; + add.filter = EVFILT_PROC; + add.fflags = NOTE_EXIT; + + timeout.tv_sec = 0; + timeout.tv_nsec = 0; + + return kevent(kqueue_id, &add, 1, NULL, 0, &timeout); + } +#endif +#ifdef HAVE_POLL + case METHOD_POLL: /* Fall through */ +#endif +#ifdef HAVE_SELECT + case METHOD_SELECT: + parent_pid = parent; + return 0; +#endif + default: + errno = ENOTSUP; + return -1; + } +} + +/* Arrange to automatically reap exited child processes */ +int +eventwait_watch_child_exit(void) +{ + switch (method) { +#ifdef HAVE_KQUEUE + case METHOD_KQUEUE:{ + struct kevent add; + struct timespec timeout; + +#ifdef HAVE_SIGPROCMASK + sigset_t chld_mask; + + sigemptyset(&chld_mask); + sigaddset(&chld_mask, SIGCHLD); +#endif + + memset(&add, 0, sizeof(add)); + add.filter = EVFILT_SIGNAL; + add.ident = SIGCHLD; + add.flags = EV_ADD | EV_ENABLE; + + timeout.tv_sec = 0; + timeout.tv_nsec = 0; + + if (sigprocmask(SIG_BLOCK, &chld_mask, NULL) < 0) + return -1; + + return kevent(kqueue_id, &add, 1, NULL, 0, &timeout); + } +#endif + default: + install_sig_handler(SIGCHLD, reaper); + return 0; + } +} + +/** Wait for an event to occur. Only returns on error or when something + * happens. + * \return The file descriptor or pid of a triggered event, or -1 on error. + */ +int +eventwait(void) +{ + switch (method) { +#ifdef HAVE_KQUEUE + case METHOD_KQUEUE:{ + struct kevent triggered[2]; + int res; + + while (1) { + res = kevent(kqueue_id, NULL, 0, triggered, 2, NULL); + if (res == 1) { + if (triggered[0].filter == EVFILT_SIGNAL) { + reap_children(); + continue; + } else + return triggered[0].ident; + } else if (res == 2) { + if (triggered[0].filter == EVFILT_SIGNAL) { + reap_children(); + return triggered[1].ident; + } else if (triggered[1].filter == EVFILT_SIGNAL) { + reap_children(); + return triggered[0].ident; + } + } else if (res < 0) + return -1; + } + } +#endif +#if defined(HAVE_POLL) + case METHOD_POLL:{ + /* It's more complex to use poll(), since it can only poll + * file descriptor events, not process events too. Wake up every + * 5 seconds to see if the given pid has turned into 1. + */ + int timeout; + int res; + + if (parent_pid > 0) + timeout = 5000; + else + timeout = -1; + + while (1) { + res = poll(poll_fds, pollfd_len, timeout); + if (res > 0) { + int n; + for (n = 0; n < pollfd_len; n++) + if (poll_fds[n].revents & POLLIN) + return poll_fds[n].fd; + } else if (res == 0 && parent_pid) { +#ifdef HAVE_GETPPID + if (getppid() == 1) + /* Parent rocess no longer exists; parent is now init */ + return parent_pid; +#endif + } else if (res < 0) + return -1; + } + } +#endif +#ifdef HAVE_SELECT + case METHOD_SELECT:{ + /* It's more complex to use select(), since it can only poll + * file descriptor events, not process events too. Wake up every + * 5 seconds to see if the given pid has turned into 1. + */ + struct timeval timeout, *tout; + int res; + + if (parent_pid > 0) + tout = &timeout; + else + tout = NULL; + + while (1) { + fd_set local_readers; + int n; + + timeout.tv_sec = 5; + timeout.tv_usec = 0; + + FD_ZERO(&local_readers); + + for (n = 0; n < maxd; n++) + if (FD_ISSET(n, &readers)) + FD_SET(n, &local_readers); + + res = select(maxd, &local_readers, NULL, NULL, tout); + if (res > 0) { + int n; + for (n = 0; n < maxd; n++) + if (FD_ISSET(n, &local_readers)) + return n; + } else if (res == 0 && parent_pid) { +#ifdef HAVE_GETPPID + if (getppid() == 1) + /* Parent process no longer exists; parent is now init */ + return parent_pid; +#endif + } else if (res < 0) + return -1; + } + } +#endif + default: + return -1; + } +} + +/* Wrappers for perror */ +void +penn_perror(const char *err) +{ + lock_file(stderr); + fprintf(stderr, "info_slave: %s: %s\n", err, strerror(errno)); + unlock_file(stderr); +} + +/* Wrapper for fputs(foo,stderr) */ +void +fputerr(const char *msg) +{ + lock_file(stderr); + fputs(msg, stderr); + fputc('\n', stderr); + unlock_file(stderr); +} diff --git a/src/intmap.c b/src/intmap.c new file mode 100644 index 0000000..e368793 --- /dev/null +++ b/src/intmap.c @@ -0,0 +1,479 @@ +/** + * \file intmap.c + * \brief Implementation of integer-keyed maps. + * + * Uses patricia trees to efficiently store sparse integer maps. Keys + * are unsigned 32 bit integers, and thus well suited for a radix tree + * implementation. Simpler than balanced binary trees (Compare the + * amount of code in strtree.c, which implements a red-black tree, + * with this), and comparable in number of nodes visited while walking + * the tree. + * + * To summarize, a patricia tree is a type of binary tree where + * branching is determined by looking at a single bit of the key, + * instead of the entire thing. There are no null links; each link + * either points to a node with a higher bit to compare, or back at + * itself or an ancestor node. When searching the tree, if you come + * upon a backwards or self link, the current node has every bit + * that's been checked so far in common with the search key. You then + * compare the search key to the node's key to see if it matches. If + * it doesn't, the search key isn't present. Only a few bits are + * typically looked at when walking down the tree. + * + * There are various properties of patricia trees that aren't used at + * all in this (Like finding all keys that have a particular + * prefix). However, consider using them in a rewrite of the prefix + * table code... + * + * Normally patricia trees use the leftmost bit as position 0. I've + * found that when using the small integers that are typical for what + * these trees are used for on Penn, going right to left produces a + * slightly shallower tree, because with the leftmost bit as 0, + * everything hangs off of the root node's 0 branch. The drawback to + * rightmost is that you can't walk the nodes in sorted order. Which + * is okay because we don't need to do that. + * + * The implementation is based loosely on ones found at + * http://www.mcdowella.demon.co.uk/Patricia.html and in the book + *
      Algorithms in C, 3rd Edition
    by Robert Sedgewick. + */ + +#include "config.h" + + +/* Uncomment this to turn off various consistency checks. Not + recommended yet. */ +/* #define NDEBUG */ + +#ifdef HAVE_STDINT_H +#include +#endif +#include +#include +#include + +#include "conf.h" +#include "externs.h" +#include "mymalloc.h" +#include "intmap.h" +#include "confmagic.h" + +/** Structure that represents a node in a patricia tree. */ +typedef struct patricia { + im_key key; /**< Key value */ + int bit; /**< Which bit to test in this node */ + void *data; /**< Pointer to data */ + struct patricia *links[2]; /**< Links to nodes to branch to based on set bit */ +} patricia; + +/** Integer map struct */ +struct intmap { + int64_t count; /**< Number of elements in tree */ + patricia *root; /**< pointer to root of tree */ +}; + +#define MAX_BIT 31 +/* #define MAX_BIT 63 */ + +slab *intmap_slab = NULL; /**< Allocator for patricia nodes */ + +/** Return the number of elements in an integer map, or -1 on error + (Passing a NULL pointer instead of a map). */ +int64_t +im_count(intmap *im) +{ + if (im) + return im->count; + else + return -1; +} + +/** Allocate and initialize a new integer map. */ +intmap * +im_new(void) +{ + intmap *im; + im = mush_malloc(sizeof *im, "int_map"); + if (!intmap_slab) { + intmap_slab = slab_create("patricia tree nodes", sizeof(struct patricia)); + slab_set_opt(intmap_slab, SLAB_ALLOC_BEST_FIT, 1); + } + im->count = 0; + im->root = NULL; + return im; +} + +static void +pat_destroy(patricia *node) +{ + int n; + + if (!node) + return; + + for (n = 0; n < 2; n++) + if (node->links[n]->bit > node->bit) + pat_destroy(node->links[n]); + + slab_free(intmap_slab, node); +} + +/** Deallocate an integer map. All data pointers that need to be freed + * qmust be deallocated seperately before this, or you'll get a memory + * leak. + * \param im the map to delete. + */ +void +im_destroy(intmap *im) +{ + if (im) { + pat_destroy(im->root); + mush_free(im, "int_map"); + } +} + +/* Returns 1 if a given bit is set, 0 if not */ +#define digit(n, pos) (!!((n) & (1U << (pos)))) + +/* More traditional right to left scanning version */ +/* #define digit(n, pos) (!!((n) & (1U << (31 - (pos))))) */ + +/* Returns the node matching the key or its prefix */ +static patricia * +pat_search(patricia *node, im_key key, int bit) +{ + assert(node); + + if (node->bit <= bit) + return node; + else + return pat_search(node->links[digit(key, node->bit)], key, node->bit); +} + +/** Look up an element in the map. + * \param im the map. + * \param key the key to look up. + * \returns the value of the data stored under that key, or NULL + */ +void * +im_find(intmap *im, im_key key) +{ + patricia *node; + + if (!im->root) + return NULL; + + node = pat_search(im->root, key, -1); + + if (node->key == key) + return node->data; + else + return NULL; +} + +/** Test if a particular key exists in a map. + * \param im the map. + * \param key the key to look up. + * \return true if the key is present, false otherwise. + */ +bool +im_exists(intmap *im, im_key key) +{ + patricia *node; + + if (!im->root) + return 0; + node = pat_search(im->root, key, -1); + return node->key == key; +} + +/** Insert a new element into the map. + * \param im the map to insert into. + * \param key the key + * \param data Pointer to data to store under this key. + * \return true on success, false on failure (Usually a duplicate key) + */ +bool +im_insert(intmap *im, im_key key, void *data) +{ + patricia *here, *newnode, *prev = NULL; + int bit, prevbit = 0; + + newnode = slab_malloc(intmap_slab, im->root); + newnode->key = key; + newnode->data = data; + newnode->links[0] = newnode->links[1] = newnode; + + /* First key added to tree */ + if (!im->root) { + newnode->bit = 0; + im->root = newnode; + im->count += 1; + assert(im->count == 1); + return true; + } + + here = pat_search(im->root, key, -1); + if (here && here->key == key) { + /* Duplicate key fails */ + slab_free(intmap_slab, newnode); + return false; + } + + /* Not a duplicate, so key and here->key /will/ differ in at least one + bit. No need to make sure that bit doesn't go > 31 */ + for (bit = 0; digit(key, bit) == digit(here->key, bit); bit++) ; + + newnode->bit = bit; + + if (bit < im->root->bit) { + newnode->links[digit(im->root->key, bit)] = im->root; + im->root = newnode; + im->count += 1; + assert(im->count > 1); + return true; + } + + for (here = im->root;;) { + int i; + if (here->bit == bit) { + newnode->bit = bit + 1; + here->links[digit(key, bit)] = newnode; + im->count += 1; + assert(im->count > 1); + return true; + } + if (here->bit > bit || (prev && here->bit <= prev->bit)) { + prev->links[prevbit] = newnode; + newnode->links[digit(here->key, bit)] = here; + im->count += 1; + assert(im->count > 1); + return true; + } + + prev = here; + i = digit(key, here->bit); + here = prev->links[i]; + prevbit = i; + } + + /* Not reached */ + assert(0); + return false; +} + + +/** Delete a key from the map. + * \param im the map. + * \param key the key to delete. + * \return true on success, false on failure (Key not present?) + */ +bool +im_delete(intmap *im, im_key key) +{ + patricia *parent = NULL, *firstparent = NULL, *grandparent = NULL; + patricia *here = im->root; + + if (!here) + return false; + + while (1) { + int x = digit(key, here->bit); + + grandparent = parent; + parent = here; + here = here->links[x]; + + assert(here); + + if (here->key == key && !firstparent) + firstparent = parent; + + if (here->bit <= parent->bit) + break; + } + + /* Key not found? */ + if (here->key != key) + return false; + + /* Case 1: key is the only node in tree */ + if (im->root == here && here->links[0] == here && here->links[1] == here) { + slab_free(intmap_slab, im->root); + im->root = NULL; + im->count -= 1; + assert(im->count == 0); + return true; + } + + /* Case 2: node points to itself. Edit it out. */ + if (parent->key == key) { + int i; + patricia *replacement; + + i = (here->links[0] == here); + replacement = here->links[i]; + + if (replacement != here) { + if (!grandparent || grandparent == here) + im->root = replacement; + else + grandparent->links[grandparent->links[1] == parent] = replacement; + } else + grandparent->links[grandparent->links[1] == parent] = grandparent; + + slab_free(intmap_slab, here); + im->count -= 1; + assert(im->count >= 1); + return true; + } + + /* Case 3: Node with children pointing up to it. */ + { + patricia *otherlink; + + if (firstparent == parent) + im->root = parent; + else + firstparent->links[firstparent->links[1] == here] = parent; + + otherlink = parent->links[parent->links[0] == here]; + if (here == grandparent) { + int i; + patricia *other; + + i = (here->links[0] == parent); + other = parent->links[parent->links[0] == here]; + parent->links[i] = here->links[i]; + parent->links[1 - i] = other; + if (parent->links[0] == here) + parent->links[0] = parent; + if (parent->links[1] == here) + parent->links[1] = parent; + parent->bit = here->bit; + slab_free(intmap_slab, here); + im->count -= 1; + assert(im->count >= 1); + return true; + } + + grandparent->links[grandparent->links[1] == parent] = otherlink; + parent->links[0] = here->links[0]; + if (parent->links[0] == here) + parent->links[0] = parent; + parent->links[1] = here->links[1]; + if (parent->links[1] == here) + parent->links[1] = parent; + parent->bit = here->bit; + slab_free(intmap_slab, here); + im->count -= 1; + assert(im->count >= 1); + return true; + } +} + +int format_long(intmax_t n, char *buff, char **bp, int maxlen, int base); + +static void +pat_list_nodes(patricia *node, FILE * fp) +{ + int n; + char tmpbuf[100]; + char *bp = tmpbuf; + + if (!node) + return; + + format_long(node->key, tmpbuf, &bp, 99, 2); + *bp = '\0'; + + fprintf(fp, + "node%u [label=\"{ key = 0b%s (%u) | bit = %d | { 0 | 1 } }\", ", + node->key, tmpbuf, node->key, node->bit); + if (node->links[0]->bit > node->bit && node->links[1]->bit > node->bit) + fputs("fillcolor=1", fp); + else if (node->links[0]->bit <= node->bit && node->links[1]->bit <= node->bit) + fputs("fillcolor=3", fp); + else + fputs("fillcolor=2", fp); + + fputs("];\n", fp); + + for (n = 0; n < 2; n++) { + if (node->links[n]->bit > node->bit) + pat_list_nodes(node->links[n], fp); + } +} + +static void +pat_list_links(patricia *node, FILE * fp) +{ + int i; + const char *edge_styles[] = { "style=dashed,arrowhead=open", + "style=solid,arrowhead=normal" + }; + + if (!node) + return; + + for (i = 0; i < 2; i++) { + if (node->links[i]) { + fprintf(fp, "node%u:b%d -> node%u:key [%s];\n", node->key, i, + node->links[i]->key, + edge_styles[node->links[i]->bit > node->bit]); + if (node->links[i]->bit > node->bit) + pat_list_links(node->links[i], fp); + } + } +} + +/** Dump a representation of an intmap into a file, using the dot language. + * Use from a debugger: + * \verbatim + * (gdb)print im_dump_graph(queue_map, "queue.dot") + * \endverbatim + * and then turn into an image: + * \verbatim + * # dot -Tpng -o queue.png queue.dot + * \endverbatim + * (dot is part of the graphviz package) + * \param im the map to print. + * \param filename The output file name. + */ +void +im_dump_graph(intmap *im, const char *filename) +{ + FILE *fp; + + if (!im || !filename) + return; + + fp = fopen(filename, "w"); + + if (!fp) { + penn_perror("fopen"); + return; + } + + fputs("digraph patricia { \n", fp); + fputs("node [shape=Mrecord, colorscheme=blues3, style=filled];\n", fp); + pat_list_nodes(im->root, fp); + pat_list_links(im->root, fp); + fputs("}\n", fp); + fclose(fp); +} + +/** Header line for @stats/tables for intmaps */ +void +im_stats_header(dbref player) +{ + notify(player, "Map Entries ~Memory"); +} + +/** @stats/tables line */ +void +im_stats(dbref player, intmap *im, const char *name) +{ + notify_format(player, "%-11s %7lld %7u", name, (long long) im->count, + (unsigned int) (sizeof(*im) + (sizeof(patricia) * im->count))); +} diff --git a/src/lmathtab.c b/src/lmathtab.c new file mode 100644 index 0000000..5794268 --- /dev/null +++ b/src/lmathtab.c @@ -0,0 +1,276 @@ +/* ANSI-C code produced by gperf version 3.0.3p1 */ +/* Command-line: gperf --output-file lmathtab.c lmathtab.gperf */ +/* Computed positions: -k'1-2,5' */ + +#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \ + && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \ + && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \ + && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \ + && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \ + && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \ + && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \ + && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \ + && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \ + && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \ + && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \ + && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \ + && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \ + && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \ + && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \ + && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \ + && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \ + && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \ + && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \ + && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \ + && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \ + && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \ + && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126)) +/* The character set is not based on ISO-646. */ +#error "gperf generated tables don't work with this execution character set. Please report a bug to ." +#endif + +#line 11 "lmathtab.gperf" + +/** 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. */ +#line 44 "lmathtab.gperf" +struct math { + const char *name; /**< Name of the function. */ + void (*func) (char **, int, char *, char **); /**< Pointer to function code. */ +}; +/* maximum key range = 46, duplicates = 0 */ + +#ifndef GPERF_DOWNCASE +#define GPERF_DOWNCASE 1 +static unsigned char gperf_downcase[256] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + 60, 61, 62, 63, 64, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, + 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, + 122, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, + 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, + 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, + 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, + 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, + 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, + 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, + 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, + 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, + 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, + 255 +}; +#endif + +#ifndef GPERF_CASE_MEMCMP +#define GPERF_CASE_MEMCMP 1 +static int +gperf_case_memcmp(register const char *s1, register const char *s2, + register unsigned int n) +{ + for (; n > 0;) { + unsigned char c1 = gperf_downcase[(unsigned char) *s1++]; + unsigned char c2 = gperf_downcase[(unsigned char) *s2++]; + if (c1 == c2) { + n--; + continue; + } + return (int) c1 - (int) c2; + } + return 0; +} +#endif + +#ifdef __GNUC__ +__inline +#ifdef __GNUC_STDC_INLINE__ + __attribute__ ((__gnu_inline__)) +#endif +#endif + static unsigned int + math_hash(register const char *str, register unsigned int len) +{ + static unsigned char asso_values[] = { + 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, + 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, + 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, + 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, + 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, + 5, 0, 49, 49, 49, 49, 49, 49, 49, 49, + 49, 49, 49, 49, 49, 0, 25, 49, 25, 0, + 18, 49, 49, 10, 49, 49, 0, 10, 0, 5, + 49, 49, 0, 15, 10, 30, 49, 49, 3, 49, + 49, 49, 49, 49, 49, 49, 49, 0, 25, 49, + 25, 0, 18, 49, 49, 10, 49, 49, 0, 10, + 0, 5, 49, 49, 0, 15, 10, 30, 49, 49, + 3, 49, 49, 49, 49, 49, 49, 49, 49, 49, + 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, + 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, + 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, + 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, + 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, + 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, + 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, + 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, + 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, + 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, + 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, + 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, + 49, 49, 49, 49, 49, 49 + }; + register int hval = len; + + switch (hval) { + default: + hval += asso_values[(unsigned char) str[4]]; + /*FALLTHROUGH*/ case 4: + case 3: + case 2: + hval += asso_values[(unsigned char) str[1]]; + /*FALLTHROUGH*/ case 1: + hval += asso_values[(unsigned char) str[0]]; + break; + } + return hval; +} + +#ifdef __GNUC__ +__inline +#ifdef __GNUC_STDC_INLINE__ + __attribute__ ((__gnu_inline__)) +#endif +#endif + struct math *math_hash_lookup(register const char *str, + register unsigned int len) +{ + enum { + TOTAL_KEYWORDS = 25, + MIN_WORD_LENGTH = 2, + MAX_WORD_LENGTH = 9, + MIN_HASH_VALUE = 3, + MAX_HASH_VALUE = 48 + }; + + static unsigned char lengthtable[] = { + 0, 0, 0, 3, 4, 0, 0, 2, 3, 0, 0, 3, 0, 3, + 4, 0, 6, 0, 3, 9, 0, 6, 7, 3, 0, 0, 8, 0, + 3, 4, 0, 6, 4, 3, 0, 0, 0, 0, 3, 0, 0, 6, + 0, 3, 0, 0, 6, 4, 3 + }; + static struct math wordlist[] = { + {"", NULL}, {"", NULL}, {"", NULL}, +#line 60 "lmathtab.gperf" + {"AND", math_and}, +#line 61 "lmathtab.gperf" + {"NAND", math_nand}, + {"", NULL}, {"", NULL}, +#line 62 "lmathtab.gperf" + {"OR", math_or}, +#line 63 "lmathtab.gperf" + {"NOR", math_nor}, + {"", NULL}, {"", NULL}, +#line 64 "lmathtab.gperf" + {"XOR", math_xor}, + {"", NULL}, +#line 59 "lmathtab.gperf" + {"MAX", math_max}, +#line 69 "lmathtab.gperf" + {"MEAN", math_mean}, + {"", NULL}, +#line 70 "lmathtab.gperf" + {"MEDIAN", math_median}, + {"", NULL}, +#line 54 "lmathtab.gperf" + {"MOD", math_modulo}, +#line 57 "lmathtab.gperf" + {"REMAINDER", math_remainder}, + {"", NULL}, +#line 55 "lmathtab.gperf" + {"MODULO", math_modulo}, +#line 56 "lmathtab.gperf" + {"MODULUS", math_modulo}, +#line 58 "lmathtab.gperf" + {"MIN", math_min}, + {"", NULL}, {"", NULL}, +#line 53 "lmathtab.gperf" + {"FLOORDIV", math_floordiv}, + {"", NULL}, +#line 49 "lmathtab.gperf" + {"ADD", math_add}, +#line 65 "lmathtab.gperf" + {"BAND", math_band}, + {"", NULL}, +#line 71 "lmathtab.gperf" + {"STDDEV", math_stddev}, +#line 67 "lmathtab.gperf" + {"BXOR", math_bxor}, +#line 66 "lmathtab.gperf" + {"BOR", math_bor}, + {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}, +#line 52 "lmathtab.gperf" + {"DIV", math_div}, + {"", NULL}, {"", NULL}, +#line 73 "lmathtab.gperf" + {"DIST3D", math_dist3d}, + {"", NULL}, +#line 51 "lmathtab.gperf" + {"MUL", math_mul}, + {"", NULL}, {"", NULL}, +#line 72 "lmathtab.gperf" + {"DIST2D", math_dist2d}, +#line 68 "lmathtab.gperf" + {"FDIV", math_fdiv}, +#line 50 "lmathtab.gperf" + {"SUB", math_sub} + }; + + if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH) { + register int key = math_hash(str, len); + + if (key <= MAX_HASH_VALUE && key >= 0) + if (len == lengthtable[key]) { + register const char *s = wordlist[key].name; + + if ((((unsigned char) *str ^ (unsigned char) *s) & ~32) == 0 + && !gperf_case_memcmp(str, s, len)) + return &wordlist[key]; + } + } + return 0; +} + +#line 74 "lmathtab.gperf" + + +typedef struct math MATH; diff --git a/src/lmathtab.gperf b/src/lmathtab.gperf new file mode 100644 index 0000000..b7e1016 --- /dev/null +++ b/src/lmathtab.gperf @@ -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; + + diff --git a/src/lock.c b/src/lock.c index d32c126..91f0192 100644 --- a/src/lock.c +++ b/src/lock.c @@ -48,42 +48,43 @@ #include "strtree.h" #include "privtab.h" #include "parse.h" +#include "htab.h" #include "confmagic.h" /* If any lock_type ever contains the character '|', reading in locks * from the db will break. */ -const lock_type Basic_Lock = "Basic"; /**< Name of basic lock */ -const lock_type Enter_Lock = "Enter"; /**< Name of enter lock */ -const lock_type Use_Lock = "Use"; /**< Name of use lock */ -const lock_type Zone_Lock = "Zone"; /**< Name of zone lock */ -const lock_type Page_Lock = "Page"; /**< Name of page lock */ -const lock_type Tport_Lock = "Teleport"; /**< Name of teleport lock */ -const lock_type Speech_Lock = "Speech"; /**< Name of speech lock */ -const lock_type Listen_Lock = "Listen"; /**< Name of listen lock */ -const lock_type Command_Lock = "Command"; /**< Name of command lock */ -const lock_type Parent_Lock = "Parent"; /**< Name of parent lock */ -const lock_type Link_Lock = "Link"; /**< Name of link lock */ -const lock_type Leave_Lock = "Leave"; /**< Name of leave lock */ -const lock_type Drop_Lock = "Drop"; /**< Name of drop lock */ -const lock_type Give_Lock = "Give"; /**< Name of give lock */ -const lock_type Mail_Lock = "Mail"; /**< Name of mail lock */ -const lock_type Follow_Lock = "Follow"; /**< Name of follow lock */ -const lock_type Examine_Lock = "Examine"; /**< Name of examine lock */ -const lock_type Chzone_Lock = "Chzone"; /**< Name of chzone lock */ -const lock_type Forward_Lock = "Forward"; /**< Name of forward lock */ -const lock_type Control_Lock = "Control"; /**< Name of control lock */ -const lock_type Dropto_Lock = "Dropto"; /**< Name of dropto lock */ -const lock_type Destroy_Lock = "Destroy"; /**< Name of destroy lock */ -const lock_type Interact_Lock = "Interact"; /**< Name of interaction lock */ -const lock_type Take_Lock = "Take"; /**< Name of take lock */ -const lock_type Open_Lock = "Open"; /**< Name of Open lock */ -const lock_type MailForward_Lock = "MailForward"; /**< Name of mailforward lock */ +lock_type Basic_Lock = "Basic"; /**< Name of basic lock */ +lock_type Enter_Lock = "Enter"; /**< Name of enter lock */ +lock_type Use_Lock = "Use"; /**< Name of use lock */ +lock_type Zone_Lock = "Zone"; /**< Name of zone lock */ +lock_type Page_Lock = "Page"; /**< Name of page lock */ +lock_type Tport_Lock = "Teleport"; /**< Name of teleport lock */ +lock_type Speech_Lock = "Speech"; /**< Name of speech lock */ +lock_type Listen_Lock = "Listen"; /**< Name of listen lock */ +lock_type Command_Lock = "Command"; /**< Name of command lock */ +lock_type Parent_Lock = "Parent"; /**< Name of parent lock */ +lock_type Link_Lock = "Link"; /**< Name of link lock */ +lock_type Leave_Lock = "Leave"; /**< Name of leave lock */ +lock_type Drop_Lock = "Drop"; /**< Name of drop lock */ +lock_type Give_Lock = "Give"; /**< Name of give lock */ +lock_type Mail_Lock = "Mail"; /**< Name of mail lock */ +lock_type Follow_Lock = "Follow"; /**< Name of follow lock */ +lock_type Examine_Lock = "Examine"; /**< Name of examine lock */ +lock_type Chzone_Lock = "Chzone"; /**< Name of chzone lock */ +lock_type Forward_Lock = "Forward"; /**< Name of forward lock */ +lock_type Control_Lock = "Control"; /**< Name of control lock */ +lock_type Dropto_Lock = "Dropto"; /**< Name of dropto lock */ +lock_type Destroy_Lock = "Destroy"; /**< Name of destroy lock */ +lock_type Interact_Lock = "Interact"; /**< Name of interaction lock */ +lock_type Take_Lock = "Take"; /**< Name of take lock */ +lock_type Open_Lock = "Open"; /**< Name of Open lock */ +lock_type MailForward_Lock = "MailForward"; /**< Name of mailforward lock */ /* Define new lock types here. */ /** Table of lock names and permissions */ -const lock_list lock_types[] = { +lock_list lock_types[] = { {"Basic", TRUE_BOOLEXP, GOD, LF_PRIVATE, NULL}, {"Enter", TRUE_BOOLEXP, GOD, LF_PRIVATE, NULL}, {"Use", TRUE_BOOLEXP, GOD, LF_PRIVATE, NULL}, @@ -109,10 +110,11 @@ const lock_list lock_types[] = { {"Interact", TRUE_BOOLEXP, GOD, LF_PRIVATE, NULL}, {"Take", TRUE_BOOLEXP, GOD, LF_PRIVATE, NULL}, {"MailForward", TRUE_BOOLEXP, GOD, LF_PRIVATE, NULL}, - /* Add new lock types just before this line. */ {NULL, NULL_CHUNK_REFERENCE, GOD, 0, NULL} }; +HASHTAB htab_locks; + /** Table of base attributes associated with success and failure of * locks. These are the historical ones; we automatically generate * such attribute names for those that aren't in this table using @@ -147,12 +149,8 @@ static int can_write_lock(dbref player, dbref thing, lock_list *lock); static lock_list *getlockstruct(dbref thing, lock_type type); static lock_list *getlockstruct_noparent(dbref thing, lock_type type); -/** Number of locks to store in a page, assuming 4096 byte pages */ -#define LOCKS_PER_PAGE 200 - -static lock_list *free_list = NULL; - -static lock_list *next_free_lock(void); +slab *lock_slab = NULL; +static lock_list *next_free_lock(const void *hint); static void free_lock(lock_list *ll); extern int unparsing_boolexp; @@ -169,7 +167,8 @@ list_locks(char *buff, char **bp, const char *name) int first = 1; const lock_list *ptr; rp = rbuff; - for (ptr = lock_types; ptr->type != NULL; ptr++) { + for (ptr = hash_firstentry(&htab_locks); + ptr; ptr = hash_nextentry(&htab_locks)) { /* Skip those that don't match */ if (name && !string_prefix(ptr->type, name)) continue; @@ -227,22 +226,52 @@ lock_flags_long(lock_list *ll) static int -string_to_lockflag(char const *p) +string_to_lockflag(dbref player, char const *p, privbits *flag) { - int f; + privbits f; + f = string_to_privs(lock_privs, p, 0); if (!f) return -1; - return f; + *flag = f; + return 0; } /** Initialize the lock strtree. */ void init_locks(void) { + lock_list *ll; st_init(&lock_names); + + hashinit(&htab_locks, 25); + + for (ll = lock_types; ll->type && *ll->type; ll++) + hashadd(strupper(ll->type), ll, &htab_locks); + + /* TODO: Change with module hook + local_locks(); + */ } +/** Add a new lock to the table. + * \param name The name of the lock + * \param flags The default flags. + */ +void +define_lock(lock_type name, privbits flags) +{ + lock_list *newlock; + + newlock = mush_malloc(sizeof *newlock, "lock"); + newlock->type = mush_strdup(strupper(name), "lock.name"); + newlock->flags = flags; + newlock->creator = GOD; + newlock->key = TRUE_BOOLEXP; + newlock->next = NULL; + hashadd((char *) newlock->type, newlock, &htab_locks); +} + static int can_write_lock(dbref player, dbref thing, lock_list *lock) { @@ -262,53 +291,19 @@ can_write_lock(dbref player, dbref thing, lock_list *lock) static lock_list * -next_free_lock(void) +next_free_lock(const void *hint) { - lock_list *ll; - - if (!free_list) { - size_t n; - - ll = mush_malloc(sizeof(lock_list) * LOCKS_PER_PAGE, "lock_page"); - - if (!ll) - mush_panic("Unable to allocate memory for locks!"); - - for (n = 0; n < LOCKS_PER_PAGE - 1; n++) { - ll[n].type = NULL; - ll[n].key = TRUE_BOOLEXP; - ll[n].creator = NOTHING; - ll[n].flags = 0; - ll[n].next = &ll[n + 1]; - } - - ll[n].next = NULL; - ll[n].type = NULL; - ll[n].key = TRUE_BOOLEXP; - ll[n].creator = NOTHING; - ll[n].flags = 0; - - free_list = &ll[0]; + if (lock_slab == NULL) { + lock_slab = slab_create("locks", sizeof(lock_list)); + slab_set_opt(lock_slab, SLAB_ALLOC_BEST_FIT, 1); } - - ll = free_list; - free_list = ll->next; - - ll->type = NULL; - ll->key = TRUE_BOOLEXP; - - return ll; + return slab_malloc(lock_slab, hint); } static void free_lock(lock_list *ll) { - ll->type = NULL; - ll->key = TRUE_BOOLEXP; - ll->creator = NOTHING; - ll->flags = 0; - ll->next = free_list; - free_list = ll; + slab_free(lock_slab, ll); } /** Given a lock type, find a lock, possibly checking parents. @@ -396,13 +391,12 @@ getlockstruct_noparent(dbref thing, lock_type type) lock_type match_lock(lock_type type) { - int i; - for (i = 0; lock_types[i].type != NULL; i++) { - if (strcasecmp(lock_types[i].type, type) == 0) { - return lock_types[i].type; - } - } - return NULL; + lock_list *ll; + ll = hashfind(strupper(type), &htab_locks); + if (ll) + return ll->type; + else + return NULL; } /** Return the proper entry from lock_types, or NULL. @@ -412,14 +406,7 @@ match_lock(lock_type type) const lock_list * get_lockproto(lock_type type) { - const lock_list *ll; - - for (ll = lock_types; ll->type; ll++) - if (strcasecmp(type, ll->type) == 0) - return ll; - - return NULL; - + return hashfind(type, &htab_locks); } /** Add a lock to an object (primitive). @@ -437,7 +424,7 @@ get_lockproto(lock_type type) * \retval 1 success. */ int -add_lock(dbref player, dbref thing, lock_type type, boolexp key, int flags) +add_lock(dbref player, dbref thing, lock_type type, boolexp key, privbits flags) { lock_list *ll, **t; lock_type real_type = type; @@ -457,10 +444,10 @@ add_lock(dbref player, dbref thing, lock_type type, boolexp key, int flags) free_boolexp(ll->key); ll->key = key; ll->creator = player; - if (flags != -1) + if (flags != LF_DEFAULT) ll->flags = flags; } else { - ll = next_free_lock(); + ll = next_free_lock(Locks(thing)); if (!ll) { /* Oh, this sucks */ do_log(LT_ERR, 0, 0, "Unable to malloc memory for lock_list!"); @@ -469,7 +456,7 @@ add_lock(dbref player, dbref thing, lock_type type, boolexp key, int flags) ll->type = real_type; ll->key = key; ll->creator = player; - if (flags == -1) { + if (flags == LF_DEFAULT) { const lock_list *l2 = get_lockproto(real_type); if (l2) ll->flags = l2->flags; @@ -509,7 +496,8 @@ add_lock(dbref player, dbref thing, lock_type type, boolexp key, int flags) * \retval 0 failure. */ int -add_lock_raw(dbref player, dbref thing, lock_type type, boolexp key, int flags) +add_lock_raw(dbref player, dbref thing, lock_type type, boolexp key, + privbits flags) { lock_list *ll, **t; lock_type real_type = type; @@ -518,7 +506,7 @@ add_lock_raw(dbref player, dbref thing, lock_type type, boolexp key, int flags) return 0; } - ll = next_free_lock(); + ll = next_free_lock(Locks(thing)); if (!ll) { /* Oh, this sucks */ do_log(LT_ERR, 0, 0, "Unable to malloc memory for lock_list!"); @@ -527,7 +515,7 @@ add_lock_raw(dbref player, dbref thing, lock_type type, boolexp key, int flags) ll->type = real_type; ll->key = key; ll->creator = player; - if (flags == -1) { + if (flags == LF_DEFAULT) { const lock_list *l2 = get_lockproto(real_type); if (l2) ll->flags = l2->flags; @@ -608,7 +596,6 @@ free_locks(lock_list *ll) * As an extra check, we don't allow '|' in lock names because it * will confuse our db-reading routines. * - * Might destructively modify name. * * \param player the enactor, for notification. * \param thing object on which to check the lock. @@ -619,7 +606,9 @@ static lock_type check_lock_type(dbref player, dbref thing, lock_type name) { lock_type ll; - char *sp; + char user_name[BUFFER_LEN]; + char *colon; + /* Special-case for basic locks. */ if (!name || !*name) return Basic_Lock; @@ -633,27 +622,26 @@ check_lock_type(dbref player, dbref thing, lock_type name) if (getlock(thing, name) != TRUE_BOOLEXP) return name; /* Check to see if it's a well-formed user-defined lock. */ - sp = strchr(name, ':'); - if (!sp) { - notify(player, T("Unknown lock type.")); - return NULL; - } - *sp++ = '\0'; - if (!string_prefix("User", name)) { + if (!string_prefix(name, "User:")) { notify(player, T("Unknown lock type.")); return NULL; } - if (strchr(sp, '|')) { + if (strchr(name, '|')) { notify(player, T("The character \'|\' may not be used in lock names.")); return NULL; } - if (!good_atr_name(sp)) { + mush_strncpy(user_name, name, BUFFER_LEN); + colon = strchr(user_name, ':'); + if (colon) /* Should always be true */ + *colon = '\0'; + + if (!good_atr_name(user_name)) { notify(player, T("That is not a valid lock name.")); return NULL; } - return sp; + return strchr(name, ':') + 1; } /** Unlock a lock (user interface). @@ -668,12 +656,11 @@ void do_unlock(dbref player, const char *name, lock_type type) { dbref thing; - char *sp; lock_type real_type; /* check for '@unlock /' */ - sp = strchr(name, '/'); - if (sp) { + if (strchr(name, '/')) { + /* TODO: Link this to @atrlock */ notify(player, "Use @atrlock."); return; } @@ -715,11 +702,9 @@ do_lock(dbref player, const char *name, const char *keyname, lock_type type) lock_type real_type; dbref thing; boolexp key; - char *sp; /* check for '@lock /' */ - sp = strchr(name, '/'); - if (sp) { + if (strchr(name, '/')) { do_atrlock(player, name, keyname, 0); return; } @@ -754,7 +739,7 @@ do_lock(dbref player, const char *name, const char *keyname, lock_type type) } else { if ((real_type = check_lock_type(player, thing, type)) != NULL) { /* everything ok, do it */ - if (add_lock(player, thing, real_type, key, -1)) { + if (add_lock(player, thing, real_type, key, LF_DEFAULT)) { if (!AreQuiet(player, thing)) notify_format(player, T("%s(%s) - %s locked."), Name(thing), unparse_dbref(thing), real_type); @@ -874,7 +859,7 @@ fail_lock(dbref player, dbref thing, lock_type ltype, const char *def, /* Find the lock's failure attribute, if it's there */ for (lm = lock_msgs; lm->type; lm++) { if (!strcmp(lm->type, ltype)) - break; + break; } if (lm->type) { strcpy(atr, lm->failbase); @@ -911,7 +896,7 @@ fail_lock(dbref player, dbref thing, lock_type ltype, const char *def, * \retval (non-zero) lock is visual. * \retval 0 lock is not visual. */ -int +bool lock_visual(dbref thing, lock_type ltype) { lock_list *l = getlockstruct(thing, ltype); @@ -935,8 +920,8 @@ do_lset(dbref player, char *what, char *flags) dbref thing; lock_list *l; char *lname; - int flag; - int unset = 0; + privbits flag; + bool unset = 0; if ((lname = strchr(what, '/')) == NULL) { notify(player, T("No lock name given.")); @@ -952,7 +937,7 @@ do_lset(dbref player, char *what, char *flags) flags++; } - if ((flag = string_to_lockflag(flags)) < 0) { + if (string_to_lockflag(player, flags, &flag) < 0) { notify(player, T("Unrecognized lock flag.")); return; } @@ -996,7 +981,8 @@ check_zone_lock(dbref player, dbref zone, int noisy) { boolexp key = getlock(zone, Zone_Lock); if (key == TRUE_BOOLEXP) { - add_lock(GOD, zone, Zone_Lock, parse_boolexp(zone, "=me", Zone_Lock), -1); + add_lock(GOD, zone, Zone_Lock, parse_boolexp(zone, "=me", Zone_Lock), + LF_DEFAULT); if (noisy) notify_format(player, T diff --git a/src/log.c b/src/log.c index 7e87c70..93d8005 100644 --- a/src/log.c +++ b/src/log.c @@ -20,11 +20,15 @@ #endif #ifdef I_SYS_TIME #include +#ifdef TIME_WITH_SYS_TIME +#include +#endif #endif #include #ifdef I_SYS_TYPES #include #endif +#include #include "conf.h" #include "externs.h" @@ -50,6 +54,9 @@ FILE *wizlog_fp; /**< Wizard log */ FILE *tracelog_fp; /**< Trace log */ FILE *cmdlog_fp; /**< Command log */ +/* From wait.c */ +int lock_file(FILE *); +int unlock_file(FILE *); static char * quick_unparse(dbref object) @@ -79,7 +86,6 @@ quick_unparse(dbref object) static void start_log(FILE ** fp, const char *filename) { - char newfilename[256] = "\0"; static int ht_initialized = 0; FILE *f; @@ -87,7 +93,7 @@ start_log(FILE ** fp, const char *filename) *fp = stderr; } else { if (!ht_initialized) { - hashinit(&htab_logfiles, 8, sizeof(FILE *)); + hashinit(&htab_logfiles, 8); ht_initialized = 1; } if ((f = (FILE *) hashfind(strupper(filename), &htab_logfiles))) { @@ -95,12 +101,9 @@ start_log(FILE ** fp, const char *filename) *fp = f; } else { - /* Must use a buffer for MacOS file path conversion */ - strncpy(newfilename, filename, 256); - - *fp = fopen(newfilename, "a"); + *fp = fopen(filename, "a"); if (*fp == NULL) { - fprintf(stderr, T("WARNING: cannot open log %s\n"), newfilename); + fprintf(stderr, T("WARNING: cannot open log %s\n"), filename); *fp = stderr; } else { hashadd(strupper(filename), (void *) *fp, &htab_logfiles); @@ -137,13 +140,12 @@ redirect_streams(void) if (!errlog_fp) { fprintf(stderr, T("Unable to open %s. Error output to stderr.\n"), ERRLOG); } else { - + fclose(errlog_fp); if (!freopen(ERRLOG, "a", stderr)) { printf(T("Ack! Failed reopening stderr!")); exit(1); } setvbuf(stderr, NULL, _IOLBF, BUFSIZ); - fclose(errlog_fp); } #ifndef DEBUG_BYTECODE fclose(stdout); @@ -159,9 +161,10 @@ end_log(const char *filename) if (!filename || !*filename) return; if ((fp = (FILE *) hashfind(strupper(filename), &htab_logfiles))) { + lock_file(fp); fprintf(fp, "END OF LOG.\n"); fflush(fp); - fclose(fp); + fclose(fp); /* Implicit lock removal */ hashdelete(strupper(filename), &htab_logfiles); } } @@ -171,7 +174,7 @@ end_log(const char *filename) void end_all_logs(void) { - char *name, *next; + const char *name, *next; name = hash_firstentry_key(&htab_logfiles); while (name) { next = hash_nextentry_key(&htab_logfiles); @@ -238,8 +241,10 @@ do_rawlog(int logtype, const char *fmt, ...) f = stderr; break; } + lock_file(f); fprintf(f, "%s %s\n", timebuf, tbuf1); fflush(f); + unlock_file(f); } /** Log a message, with useful information. @@ -497,3 +502,10 @@ notify_activity(dbref player, int num_lines, int dump) if (!dump) notify(player, T("GAME: End recall")); } + +/* Wrapper for perror */ +void +penn_perror(const char *err) +{ + do_rawlog(LT_ERR, "%s:%s", err, strerror(errno)); +} diff --git a/src/look.c b/src/look.c index 56eebd8..db58478 100644 --- a/src/look.c +++ b/src/look.c @@ -22,15 +22,15 @@ #include "match.h" #include "ansi.h" #include "pueblo.h" +#ifdef CHAT_SYSTEM #include "extchat.h" +#endif #include "game.h" #include "command.h" #include "parse.h" #include "privtab.h" -#include "log.h" -#include "case.h" #include "confmagic.h" - +#include "log.h" static void look_exits(dbref player, dbref loc, const char *exit_name); static void look_contents(dbref player, dbref loc, const char *contents_name); @@ -50,9 +50,8 @@ void decompile_atrs(dbref player, dbref thing, const char *name, const char *pattern, const char *prefix, int skipdef); void decompile_locks(dbref player, dbref thing, const char *name, int skipdef); -static void insert_spaces(int count, int dospace, char *buff, char **bp); - extern PRIV attr_privs_view[]; +extern int real_decompose_str(char *str, char *buff, char **bp); static void look_exits(dbref player, dbref loc, const char *exit_name) @@ -186,7 +185,7 @@ look_exits(dbref player, dbref loc, const char *exit_name) if (Transparented(loc) && !(Opaque(thing))) { if (SUPPORT_PUEBLO && !texits) { texits = 1; - notify_noenter_by(loc, player, tprintf("%cUL%c", TAG_START, TAG_END)); + notify_noenter_by(loc, player, open_tag("UL")); } s1 = tbuf1; safe_tag("LI", tbuf1, &s1); @@ -350,20 +349,21 @@ look_helper_veiled(dbref player, dbref thing __attribute__ ((__unused__)), if (ShowAnsi(player)) notify_format(player, "%s%s [#%d%s]%s is veiled", ANSI_HILITE, AL_NAME(atr), - Owner(AL_CREATOR(atr)), fbuf, ANSI_NORMAL); - else - notify_format(player, - "%s [#%d%s] is veiled", AL_NAME(atr), - Owner(AL_CREATOR(atr)), fbuf); + Owner(AL_CREATOR(atr)), fbuf, ANSI_END); + else + notify_format(player, + "%s%s [#%d%s]%s is veiled", ANSI_HILITE, AL_NAME(atr), + Owner(AL_CREATOR(atr)), fbuf, ANSI_END); } else { r = safe_atr_value(atr); if (ShowAnsi(player)) notify_format(player, "%s%s [#%d%s]:%s %s", ANSI_HILITE, AL_NAME(atr), - Owner(AL_CREATOR(atr)), fbuf, ANSI_NORMAL, r); + Owner(AL_CREATOR(atr)), fbuf, ANSI_END, r); else - notify_format(player, "%s [#%d%s]: %s", AL_NAME(atr), - Owner(AL_CREATOR(atr)), fbuf, r); + notify_format(player, + "%s%s [#%d%s]:%s %s", ANSI_HILITE, AL_NAME(atr), + Owner(AL_CREATOR(atr)), fbuf, ANSI_END, r); /* Show the Lock if it has one */ if(!(AL_RLock(atr) == TRUE_BOOLEXP)) notify_format(player, "Readlock: %s", unparse_boolexp(player, AL_RLock(atr), UB_ALL )); @@ -387,15 +387,27 @@ look_helper(dbref player, dbref thing __attribute__ ((__unused__)), if (EX_PUBLIC_ATTRIBS && !strcmp(AL_NAME(atr), "DESCRIBE") && !strcmp(pattern, "*")) return 0; + if (parent == thing || !GoodObject(parent)) + parent = NOTHING; strcpy(fbuf, privs_to_letters(attr_privs_view, AL_FLAGS(atr))); r = safe_atr_value(atr); - if (ShowAnsi(player)) - notify_format(player, - "%s%s [#%d%s]:%s %s", ANSI_HILITE, AL_NAME(atr), - Owner(AL_CREATOR(atr)), fbuf, ANSI_NORMAL, r); - else - notify_format(player, "%s [#%d%s]: %s", AL_NAME(atr), - Owner(AL_CREATOR(atr)), fbuf, r); + if (ShowAnsi(player)) { + if (GoodObject(parent)) + notify_format(player, + "%s#%d/%s [#%d%s]:%s %s", ANSI_HILITE, parent, + AL_NAME(atr), Owner(AL_CREATOR(atr)), fbuf, ANSI_END, r); + else + notify_format(player, + "%s%s [#%d%s]:%s %s", ANSI_HILITE, AL_NAME(atr), + Owner(AL_CREATOR(atr)), fbuf, ANSI_END, r); + } else { + if (GoodObject(parent)) + notify_format(player, "#%d/%s [#%d%s]: %s", parent, AL_NAME(atr), + Owner(AL_CREATOR(atr)), fbuf, r); + else + notify_format(player, "%s [#%d%s]: %s", AL_NAME(atr), + Owner(AL_CREATOR(atr)), fbuf, r); + } free((Malloc_t) r); return 1; } @@ -655,8 +667,12 @@ do_look_at(dbref player, const char *name, int key) /* look at a thing in location */ if ((thing = match_result(player, name, NOTYPE, MAT_NEARBY)) == NOTHING) { dbref box; - const char *boxname = name; - box = parse_match_possessor(player, &name); + const char *boxname; + char objnamebuf[BUFFER_LEN], *objname; + boxname = name; + strcpy(objnamebuf, name); + objname = objnamebuf; + box = parse_match_possessor(player, &objname); if (box == NOTHING) { notify(player, T("I don't see that here.")); return; @@ -664,7 +680,7 @@ do_look_at(dbref player, const char *name, int key) notify_format(player, T("I can't tell which %s."), boxname); return; } - thing = match_result(box, name, NOTYPE, MAT_POSSESSION); + thing = match_result(box, objname, NOTYPE, MAT_POSSESSION); if (thing == NOTHING) { notify(player, T("I don't see that here.")); return; @@ -712,7 +728,7 @@ do_look_at(dbref player, const char *name, int key) #endif look_simple(player, thing); if (!(Opaque(thing))) - look_contents(player, thing, "Carrying:"); + look_contents(player, thing, T("Carrying:")); break; default: look_simple(player, thing); @@ -721,6 +737,7 @@ do_look_at(dbref player, const char *name, int key) } +/* TODO: Examine PennMUSH Source for do_examine function and see if we're lacking any new featuers */ /** Examine an object. * \param player the enactor doing the examining. * \param name name of object to examine. @@ -728,7 +745,7 @@ do_look_at(dbref player, const char *name, int key) * \param all if 1, include veiled attributes. */ void -do_examine(dbref player, const char *name, enum exam_type flag, int all) +do_examine(dbref player, const char *xname, enum exam_type flag, int all) { dbref thing; ATTR *a; @@ -737,6 +754,7 @@ do_examine(dbref player, const char *name, enum exam_type flag, int all) dbref exit_dbref; dbref non_div; const char *real_name = NULL; + char *name = NULL; char *attrib_name = NULL; char *tp; char *tbuf; @@ -744,12 +762,11 @@ do_examine(dbref player, const char *name, enum exam_type flag, int all) int listed = 0; PUEBLOBUFF; - if (*name == '\0') { + if (*xname == '\0') { if ((thing = Location(player)) == NOTHING) return; - attrib_name = NULL; } else { - + name = mush_strdup(xname, "de.string"); if ((attrib_name = strchr(name, '/')) != NULL) { *attrib_name = '\0'; attrib_name++; @@ -790,7 +807,9 @@ do_examine(dbref player, const char *name, enum exam_type flag, int all) safe_str(object_header(player, Owner(thing)), tbuf, &tp); *tp = '\0'; notify(player, tbuf); - mush_free((Malloc_t) tbuf, "string"); + mush_free(tbuf, "string"); + if (name) + mush_free(name, "de.string"); return; } if (ok) { @@ -903,7 +922,9 @@ do_examine(dbref player, const char *name, enum exam_type flag, int all) safe_str(object_header(player, Owner(thing)), tbuf, &tp); *tp = '\0'; notify(player, tbuf); - mush_free((Malloc_t) tbuf, "string"); + mush_free(tbuf, "string"); + if (name) + mush_free(name, "de.string"); return; } switch (Typeof(thing)) { @@ -975,7 +996,9 @@ do_examine(dbref player, const char *name, enum exam_type flag, int all) /* do nothing */ break; } - mush_free((Malloc_t) tbuf, "string"); + mush_free(tbuf, "string"); + if (name) + mush_free(name, "de.string"); } /** The score command: check a player's money. @@ -1198,12 +1221,12 @@ do_sweep(dbref player, const char *arg1) } else { if (Hearer(here) || Listener(here)) { if (Connected(here)) - notify_format(player, "%s [speech]. (connected)", Name(here)); + notify_format(player, T("%s [speech]. (connected)"), Name(here)); else - notify_format(player, "%s [speech].", Name(here)); + notify_format(player, T("%s [speech]."), Name(here)); } if (Commer(here)) - notify_format(player, "%s [commands].", Name(here)); + notify_format(player, T("%s [commands]."), Name(here)); } } } @@ -1214,9 +1237,9 @@ do_sweep(dbref player, const char *arg1) for (here = Exits(Location(player)); here != NOTHING; here = Next(here)) { if (Audible(here)) { strcpy(tbuf1, Name(here)); - for (p = tbuf1; *p && (*p != ';'); p++) ; + p = seek_char(tbuf1, ';'); *p = '\0'; - notify_format(player, "%s [broadcasting].", tbuf1); + notify_format(player, T("%s [broadcasting]."), tbuf1); } } } @@ -1238,12 +1261,12 @@ do_sweep(dbref player, const char *arg1) } else { if (Hearer(here) || Listener(here)) { if (Connected(here)) - notify_format(player, "%s [speech]. (connected)", Name(here)); + notify_format(player, T("%s [speech]. (connected)"), Name(here)); else - notify_format(player, "%s [speech].", Name(here)); + notify_format(player, T("%s [speech]."), Name(here)); } if (Commer(here)) - notify_format(player, "%s [commands].", Name(here)); + notify_format(player, T("%s [commands]."), Name(here)); } } } @@ -1361,7 +1384,7 @@ do_entrances(dbref player, const char *where, char *argv[], enum ent_type val) if (exd) { if (Location(counter) == place) { notify_format(player, - "%s(#%d) [from: %s(#%d)]", Name(counter), + T("%s(#%d) [from: %s(#%d)]"), Name(counter), counter, Name(Source(counter)), Source(counter)); exc++; } @@ -1370,7 +1393,8 @@ do_entrances(dbref player, const char *where, char *argv[], enum ent_type val) case TYPE_ROOM: if (rd) { if (Location(counter) == place) { - notify_format(player, "%s(#%d) [dropto]", Name(counter), counter); + notify_format(player, T("%s(#%d) [dropto]"), Name(counter), + counter); rc++; } } @@ -1378,7 +1402,7 @@ do_entrances(dbref player, const char *where, char *argv[], enum ent_type val) case TYPE_THING: if (td) { if (Home(counter) == place) { - notify_format(player, "%s(#%d) [home]", Name(counter), counter); + notify_format(player, T("%s(#%d) [home]"), Name(counter), counter); tc++; } } @@ -1386,7 +1410,7 @@ do_entrances(dbref player, const char *where, char *argv[], enum ent_type val) case TYPE_PLAYER: if (pd) { if (Home(counter) == place) { - notify_format(player, "%s(#%d) [home]", Name(counter), counter); + notify_format(player, T("%s(#%d) [home]"), Name(counter), counter); pc++; } } @@ -1401,7 +1425,8 @@ do_entrances(dbref player, const char *where, char *argv[], enum ent_type val) } else { notify(player, T("---------- Entrances Done ----------")); notify_format(player, - "Totals: Rooms...%d Exits...%d Objects...%d Players...%d", + T + ("Totals: Rooms...%d Exits...%d Objects...%d Players...%d"), rc, exc, tc, pc); return; } @@ -1416,267 +1441,28 @@ struct dh_args { extern char escaped_chars[UCHAR_MAX + 1]; -static void -insert_spaces(int count, int dospace, char *buff, char **bp) -{ - if (count) { - if (count >= 5) { - safe_str("[space(", buff, bp); - safe_number(count, buff, bp); - safe_str(")]", buff, bp); - } else if (count == 1) { - if (dospace) { - safe_str("%b", buff, bp); - } else { - safe_chr(' ', buff, bp); - } - } else { - /* Take care of the final %b */ - count--; - if (dospace) { - safe_str("%b", buff, bp); - count--; - } - while (count) { - safe_chr(' ', buff, bp); - count--; - if (count) { - count--; - safe_str("%b", buff, bp); - } - } - safe_str("%b", buff, bp); - } - } -} - char * decompose_str(char *what) { static char value[BUFFER_LEN]; - char *ptr, *s, *codestart; - char ansi_letter = '\0'; - int len; - int dospace; - int spaces; - int flag_depth, ansi_depth; - int digits; - - len = strlen(what); - flag_depth = 0; - ansi_depth = 0; - - /* Go through the string, escaping characters and - * turning every other space into %b. */ - - s = value; - ptr = what; -#ifdef NEVER - /* Put a \ at the beginning if it won't already be put there, - * unless it's a space, which would require %b, %r, or %t anyway */ - if (!escaped_chars[(unsigned int) *what] && !isspace((unsigned char)*what)) { - safe_chr('\\', value, &s); - } -#endif - - dospace = 1; - spaces = 0; - for (; *ptr; ptr++) { - switch (*ptr) { - case ' ': - spaces++; - break; - case '\n': - insert_spaces(spaces, dospace, value, &s); - spaces = 0; - dospace = 0; - safe_str("%r", value, &s); - break; - case '\t': - insert_spaces(spaces, dospace, value, &s); - spaces = 0; - dospace = 0; - safe_str("%t", value, &s); - break; - case ESC_CHAR: - insert_spaces(spaces, dospace, value, &s); - spaces = 0; - ptr++; - if (!*ptr) { - ptr--; - break; - } - /* Check if this is any sort of useful code. */ - if (*ptr == '[' && *(ptr + 1) && *(ptr + 2)) { - codestart = ptr; /* Save the address of the escape code. */ - ptr++; - digits = 0; /* Digit count is zero. */ - /* The following code works in this way: - * 1) If a character is a ;, we are allowed to count 2 more digits - * 2) If the digits count is 3, break out of the "ansi" code. - * 3) If the character is not a number or ;, break out. - * 4) If an 'm' is encountered, the for-loop exits. - * The only non-breaking exit occurs when the code ends with "m". - * Otherwise, we break out with the ptr pointing to the end of - * the invalid code, causing decompose() to ignore it entirely. - */ - for (; *ptr && (*ptr != 'm'); ptr++) { - if (*ptr == ';') { - if (digits == 0) { /* No double-;s are allowed. */ - digits = 3; - break; - } - digits = 0; - } else if (digits >= 2) { - digits = 3; /* If we encounter a 3-number code, break out. */ - break; - } else if (isdigit((unsigned char) *ptr)) { - digits++; /* Count the numbers we encounter. */ - } else { - digits = 3; - break; - } - } + char *vp = value; - /* 3 is the break-code. 0 means there's no ANSI at all! */ - if (!*ptr || digits == 3 || digits == 0) { - break; - } + real_decompose_str(what, value, &vp); + *vp = '\0'; - /* It IS an ansi code! It ends in "m" anyway. - * Set ptr to point to the first digit in the code. We are - * promised at this point that ptr+1 is not NUL. - */ - ptr = codestart + 1; - - /* Check if the first part of the code is two-digit (color) */ - if (*(ptr + 1) >= '0' && *(ptr + 1) <= '7') { - if (flag_depth < ansi_depth) { - safe_str(")]", value, &s); - ansi_depth--; - } - } else { /* ansi "flag", inverse, flash, underline, hilight */ - flag_depth = ansi_depth + 1; - } - /* Check to see if this is an 'ansi-reset' code. */ - if (*ptr == '0' && *(ptr + 1) == 'm') { - for (; ansi_depth > 0; ansi_depth--) { - safe_str(")]", value, &s); - } - flag_depth = 0; - ptr++; - break; - } - - ansi_depth++; - safe_str("[ansi(", value, &s); - dospace = 1; - - /* code for decompiling ansi */ - for (; isdigit((unsigned char) *ptr) || *ptr == ';'; ptr++) { - if (*ptr == ';') /* Yes, it is necessary to do it this way. */ - ptr++; - /* Break if there is an 'm' here. */ - if (!*ptr || !isdigit((unsigned char) *ptr)) - break; - /* Check to see if the code is one character long. */ - if (*(ptr + 1) == ';' || *(ptr + 1) == 'm') { - /* ANSI flag */ - switch (*ptr) { - case '1': - safe_chr('h', value, &s); - break; - case '4': - safe_chr('u', value, &s); - break; - case '5': - safe_chr('f', value, &s); - break; - case '7': - safe_chr('i', value, &s); - break; - default: /* Not a valid code. */ - break; - } - } else { - if (!*(ptr + 1)) - break; /* Sudden string end or lack of real color code. */ - ptr++; - - /* Check if this could be a real color (starts with 3 or 4) */ - if (*(ptr - 1) == '3' || *(ptr - 1) == '4') { - switch (*ptr) { - case '0': - ansi_letter = 'x'; - break; - case '1': - ansi_letter = 'r'; - break; - case '2': - ansi_letter = 'g'; - break; - case '3': - ansi_letter = 'y'; - break; - case '4': - ansi_letter = 'b'; - break; - case '5': - ansi_letter = 'm'; - break; - case '6': - ansi_letter = 'c'; - break; - case '7': - ansi_letter = 'w'; - break; - default: - break; /* Not a valid color. */ - } - /* If background color, change the letter to a capital. */ - if (*(ptr - 1) == '4') - ansi_letter = UPCASE(ansi_letter); - safe_chr(ansi_letter, value, &s); - } - /* No "else" here: If a two-digit code - * doesn't start with 3 or 4, is isn't ANSI. */ - } - } - safe_chr(',', value, &s); - } else { - ptr--; - /* This shouldn't happen if we only have ansi codes - * So if more dirty things must be added later... */ - } - break; - default: - insert_spaces(spaces, dospace, value, &s); - spaces = 0; - if (escaped_chars[(unsigned int) *ptr]) { - safe_chr('\\', value, &s); - } - safe_chr(*ptr, value, &s); - dospace = 0; - } - } - /* Now check the last space. */ - insert_spaces(spaces, dospace, value, &s); - spaces = 0; - for (; ansi_depth > 0; ansi_depth--) { - safe_str(")]", value, &s); - } - *s = '\0'; return value; } static int -decompile_helper(dbref player, dbref thing __attribute__ ((__unused__)), - dbref parent __attribute__ ((__unused__)), - const char *pattern __attribute__ ((__unused__)), - ATTR *atr, void *args) +decompile_helper(dbref player, dbref thing __attribute__ ((__unused__)), + dbref parent __attribute__ ((__unused__)), + const char *pattern + __attribute__ ((__unused__)), ATTR *atr, void *args) { struct dh_args *dh = args; ATTR *ptr; + char *avalue; + int avlen; char msg[BUFFER_LEN]; char *bp; @@ -1686,17 +1472,32 @@ decompile_helper(dbref player, dbref thing __attribute__ ((__unused__)), ptr = atr_match(AL_NAME(atr)); bp = msg; safe_str(dh->prefix, msg, &bp); - if (ptr && !strcmp(AL_NAME(atr), AL_NAME(ptr))) - safe_chr('@', msg, &bp); - else { - ptr = NULL; /* To speed later checks */ - safe_chr('&', msg, &bp); - } - safe_str(AL_NAME(atr), msg, &bp); - safe_chr(' ', msg, &bp); - safe_str(dh->name, msg, &bp); - safe_chr('=', msg, &bp); - safe_str(atr_value(atr), msg, &bp); + + avalue = atr_value(atr); + avlen = strlen(avalue); + /* If avalue includes a %r, a %t, begins or ends with a %b, or has markup, + * then use @set on the decompose_str'd value instead of &atrname */ + if (strchr(avalue, '\n') || strchr(avalue, '\t') || + strchr(avalue, TAG_START) || *avalue == ' ' || avalue[avlen - 1] == ' ') { + safe_str("@set ", msg, &bp); + safe_str(dh->name, msg, &bp); + safe_chr('=', msg, &bp); + safe_str(AL_NAME(atr), msg, &bp); + safe_chr(':', msg, &bp); + safe_str(decompose_str(avalue), msg, &bp); + } else { + if (ptr && !strcmp(AL_NAME(atr), AL_NAME(ptr))) { + safe_chr('@', msg, &bp); + } else { + ptr = NULL; /* To speed later checks */ + safe_chr('&', msg, &bp); + } + safe_str(AL_NAME(atr), msg, &bp); + safe_chr(' ', msg, &bp); + safe_str(dh->name, msg, &bp); + safe_chr('=', msg, &bp); + safe_str(avalue, msg, &bp); + } *bp = '\0'; notify(player, msg); /* Now deal with attribute flags, if not FugueEditing */ @@ -1706,7 +1507,7 @@ decompile_helper(dbref player, dbref thing __attribute__ ((__unused__)), if (dh->skipdef && ptr) { /* Standard attribute. Get the default perms, if any. */ /* Are we different? If so, do as usual */ - unsigned int npmflags = AL_FLAGS(ptr) & (~AF_PREFIXMATCH); + uint32_t npmflags = AL_FLAGS(ptr) & (~AF_PREFIXMATCH); if (AL_FLAGS(atr) != AL_FLAGS(ptr) && AL_FLAGS(atr) != npmflags) privs = privs_to_string(attr_privs_view, AL_FLAGS(atr)); } else { @@ -1718,6 +1519,8 @@ decompile_helper(dbref player, dbref thing __attribute__ ((__unused__)), return 1; } + + /** Decompile attributes on an object. * \param player the enactor. * \param thing object with attributes to decompile. @@ -1784,30 +1587,34 @@ decompile_locks(dbref player, dbref thing, const char *name, int skipdef) * \param skipdef if true, skip showing default flags on attributes/locks. */ void -do_decompile(dbref player, const char *name, const char *prefix, +do_decompile(dbref player, const char *xname, const char *prefix, enum dec_type dbflag, int skipdef) { dbref thing; const char *object = NULL; - char *attrib; + char *attrib, *name; char dbnum[40]; /* @decompile must always have an argument */ - if (!name || !*name) { + if (!xname || !*xname) { notify(player, T("What do you want to @decompile?")); return; } + name = mush_strdup(xname, "dd.string"); attrib = strchr(name, '/'); if (attrib) *attrib++ = '\0'; /* find object */ if ((thing = noisy_match_result(player, name, NOTYPE, MAT_EVERYTHING)) == - NOTHING) + NOTHING) { + mush_free(name, "dd.string"); return; + } if (IsGarbage(thing)) { notify(player, T("Garbage is garbage.")); + mush_free(name, "dd.string"); return; } sprintf(dbnum, "#%d", thing); @@ -1825,11 +1632,13 @@ do_decompile(dbref player, const char *name, const char *prefix, decompile_atrs(player, thing, Name(thing), attrib, prefix, skipdef); break; } + mush_free(name, "dd.string"); return; } /* else we have a full decompile */ if (!Can_Examine(player, thing)) { notify(player, T("Permission denied.")); + mush_free(name, "dd.string"); return; } /* determine creation and what we call the object */ @@ -1911,4 +1720,5 @@ do_decompile(dbref player, const char *name, const char *prefix, if (dbflag != DEC_FLAG) { decompile_atrs(player, thing, object, "**", prefix, skipdef); } + mush_free(name, "dd.string"); } diff --git a/src/malias.c b/src/malias.c index f01846f..b5683c8 100644 --- a/src/malias.c +++ b/src/malias.c @@ -39,6 +39,9 @@ #ifdef I_SYS_TIME #include +#ifdef TIME_WITH_SYS_TIME +#include +#endif #else #include #endif @@ -151,7 +154,7 @@ do_malias_create(dbref player, char *alias, char *tolist) good = "`$_-.'"; /* Make sure that the name contains legal characters only */ for (scan = alias + 1; scan && *scan; scan++) { - if (isalpha((unsigned char) *scan) || isdigit((unsigned char) *scan)) + if (isalnum((unsigned char) *scan)) continue; if (!strchr(good, *scan)) { notify(player, T("MAIL: Invalid character in mail alias.")); @@ -165,16 +168,12 @@ do_malias_create(dbref player, char *alias, char *tolist) } if (!ma_size) { ma_size = MA_INC; - malias = - (struct mail_alias *) mush_malloc(sizeof(struct mail_alias) * - ma_size, "malias_list"); + malias = mush_calloc(ma_size, sizeof(struct mail_alias), "malias_list"); } else if (ma_top >= ma_size) { ma_size += MA_INC; - m = - (struct mail_alias *) mush_malloc(sizeof(struct mail_alias) * - (ma_size), "malias_list"); + m = mush_calloc(ma_size, sizeof(struct mail_alias), "malias_list"); memcpy(m, malias, sizeof(struct mail_alias) * ma_top); - mush_free((Malloc_t) malias, "malias_list"); + mush_free(malias, "malias_list"); malias = m; } i = 0; @@ -238,7 +237,7 @@ do_malias_create(dbref player, char *alias, char *tolist) return; } m = &malias[ma_top]; - m->members = (dbref *) mush_malloc(sizeof(dbref) * i, "malias_members"); + m->members = mush_calloc(i, sizeof(dbref), "malias_members"); memcpy(m->members, alist, sizeof(dbref) * i); na = alias + 1; @@ -559,8 +558,8 @@ do_malias_set(dbref player, char *alias, char *tolist) return; } if (m->members) - mush_free((Malloc_t) m->members, "malias_members"); - m->members = (dbref *) mush_malloc(sizeof(dbref) * i, "malias_members"); + mush_free(m->members, "malias_members"); + m->members = mush_calloc(i, sizeof(dbref), "malias_members"); memcpy(m->members, alist, sizeof(dbref) * i); m->size = i; notify(player, T("MAIL: Alias list set.")); @@ -774,12 +773,11 @@ do_malias_add(dbref player, char *alias, char *tolist) notify(player, T("MAIL: No valid recipients for alias-list!")); return; } - members = - (dbref *) mush_malloc(sizeof(dbref) * (i + m->size), "malias_members"); + members = mush_calloc(i + m->size, sizeof(dbref), "malias_members"); memcpy(members, m->members, sizeof(dbref) * m->size); memcpy(&members[m->size], alist, sizeof(dbref) * i); - mush_free((Malloc_t) m->members, "malias_members"); + mush_free(m->members, "malias_members"); m->members = members; m->size += i; @@ -1003,9 +1001,7 @@ load_malias(FILE * fp) ma_size = ma_top; if (ma_top > 0) - malias = - (struct mail_alias *) mush_malloc(sizeof(struct mail_alias) * - ma_size, "malias_list"); + malias = mush_calloc(ma_size, sizeof(struct mail_alias), "malias_list"); else malias = NULL; @@ -1022,8 +1018,7 @@ load_malias(FILE * fp) m->size = getref(fp); if (m->size > 0) { - m->members = - (dbref *) mush_malloc(m->size * sizeof(dbref), "malias_members"); + m->members = mush_calloc(m->size, sizeof(dbref), "malias_members"); for (j = 0; j < m->size; j++) { m->members[j] = getref(fp); } diff --git a/src/markup.c b/src/markup.c new file mode 100644 index 0000000..4f0b3e4 --- /dev/null +++ b/src/markup.c @@ -0,0 +1,2252 @@ +/** + * \file markup.c + * + * \brief Markup handling in PennMUSH strings. + * + * + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include "copyrite.h" +#include "conf.h" +#include "case.h" +#include "pueblo.h" +#include "parse.h" +#include "externs.h" +#include "ansi.h" +#include "mymalloc.h" +#include "log.h" +#include "game.h" +#include "confmagic.h" + +#define ANSI_BEGIN "\x1B[" +#define ANSI_FINISH "m" + +/* COL_* defines */ + +#define CBIT_HILITE (1) /**< ANSI hilite attribute bit */ +#define CBIT_INVERT (2) /**< ANSI inverse attribute bit */ +#define CBIT_FLASH (4) /**< ANSI flash attribute bit */ +#define CBIT_UNDERSCORE (8) /**< ANSI underscore attribute bit */ + +#define COL_NORMAL (0) /**< ANSI normal */ +#define COL_HILITE (1) /**< ANSI hilite attribute value */ +#define COL_UNDERSCORE (4) /**< ANSI underscore attribute value */ +#define COL_FLASH (5) /**< ANSI flag attribute value */ +#define COL_INVERT (7) /**< ANSI inverse attribute value */ + +#define COL_BLACK (30) /**< ANSI color black */ +#define COL_RED (31) /**< ANSI color red */ +#define COL_GREEN (32) /**< ANSI color green */ +#define COL_YELLOW (33) /**< ANSI color yellow */ +#define COL_BLUE (34) /**< ANSI color blue */ +#define COL_MAGENTA (35) /**< ANSI color magenta */ +#define COL_CYAN (36) /**< ANSI color cyan */ +#define COL_WHITE (37) /**< ANSI color white */ + +/* Now the code */ + +static int write_ansi_close(char *buff, char **bp); +static int write_ansi_letters(const ansi_data *cur, char *buff, char **bp); +static int safe_markup(char const *a_tag, char *buf, char **bp, char type); +static int + safe_markup_cancel(char const *a_tag, char *buf, char **bp, char type); +static int compare_starts(const void *a, const void *b); +static int escape_marked_str(char **str, char *buff, char **bp); + +const char *is_allowed_tag(const char *s, unsigned int len); + +static const ansi_data ansi_null = { 0, 0, 0, 0 }; + +/* ARGSUSED */ +FUNCTION(fun_stripansi) +{ + char *cp; + cp = remove_markup(args[0], NULL); + safe_str(cp, buff, bp); +} + +#ifdef ANSI_DEBUG +/* ARGSUSED */ +void inspect_ansi_string(ansi_string *as, dbref who); +FUNCTION(fun_ansiinspect) +{ + char *ptr; + ansi_string *as; + char choice; + int strnum; + if (nargs < 2 || !args[0] || !*args[0]) { + choice = 'r'; + strnum = 0; + } else { + choice = *args[0]; + strnum = 1; + } + switch (choice) { + case 'i': + as = parse_ansi_string(args[strnum]); + inspect_ansi_string(as, executor); + free_ansi_string(as); + break; + case 'r': + for (ptr = args[strnum]; *ptr; ptr++) { + if (*ptr == TAG_START) + *ptr = '<'; + if (*ptr == TAG_END) + *ptr = '>'; + } + safe_str(args[strnum], buff, bp); + break; + case 'l': + safe_integer(arglens[strnum], buff, bp); + break; + default: + safe_str("i: inspect r: raw l: length", buff, bp); + break; + } +} +#endif + +/* ARGSUSED */ +FUNCTION(fun_ansi) +{ + ansi_data colors; + char *save = *bp; + char *p; + int i; + + /* Populate the colors struct */ + define_ansi_data(&colors, args[0]); + if (!(colors.bits || colors.offbits || colors.fore || colors.back)) { + if (!safe_strl(args[1], arglens[1], buff, bp)) + /* write_ansi_close(buff, bp); */ + return; + } + + /* Write the colors to buff */ + if (write_ansi_data(&colors, buff, bp)) { + *bp = save; + return; + } + + /* If the contents overrun the buffer, we + * place an ANSI_ENDALL tag at the end */ + if (safe_str(args[1], buff, bp) || write_ansi_close(buff, bp)) { + p = buff + BUFFER_LEN - 6; /* */ + for (i = 10; i > 0 && *p != TAG_START; i--, p--) ; + if (i > 0) { + /* There's an extant tag, let's just replace that. */ + *bp = p; + safe_str(ANSI_ENDALL, buff, bp); + } else { + *bp = buff + BUFFER_LEN - 6; + safe_str(ANSI_ENDALL, buff, bp); + } + } +} + +/* File generated by gperf */ +#include "htmltab.c" + +/* ARGSUSED */ +FUNCTION(fun_html) +{ + if (!Director(executor)) + safe_str(T(e_perm), buff, bp); + else + safe_tag(args[0], buff, bp); +} + +/* ARGSUSED */ +FUNCTION(fun_tag) +{ + int i; + if (!Director(executor) + && !is_allowed_tag(args[0], arglens[0])) { + safe_str("#-1", buff, bp); + return; + } + safe_chr(TAG_START, buff, bp); + safe_chr(MARKUP_HTML, buff, bp); + safe_strl(args[0], arglens[0], buff, bp); + for (i = 1; i < nargs; i++) { + if (ok_tag_attribute(executor, args[i])) { + safe_chr(' ', buff, bp); + safe_strl(args[i], arglens[i], buff, bp); + } + } + safe_chr(TAG_END, buff, bp); +} + +/* ARGSUSED */ +FUNCTION(fun_endtag) +{ + if (!Director(executor) && !is_allowed_tag(args[0], arglens[0])) + safe_str("#-1", buff, bp); + else + safe_tag_cancel(args[0], buff, bp); +} + +/* ARGSUSED */ +FUNCTION(fun_tagwrap) +{ + if (!Director(executor) && !is_allowed_tag(args[0], arglens[0])) + safe_str("#-1", buff, bp); + else { + if (nargs == 2) + safe_tag_wrap(args[0], NULL, args[1], buff, bp, executor); + else + safe_tag_wrap(args[0], args[1], args[2], buff, bp, executor); + } +} + +/** A version of strlen that ignores ansi and HTML sequences. + * \param p string to get length of. + * \return length of string p, not including ansi/html sequences. + */ +int +ansi_strlen(const char *p) +{ + int i = 0; + + if (!p) + return 0; + + while (*p) { + if (*p == TAG_START) { + while ((*p) && (*p != TAG_END)) + p++; + } else if (*p == ESC_CHAR) { + while ((*p) && (*p != 'm')) + p++; + } else { + i++; + } + p++; + } + return i; +} + +/** Returns the apparent length of a string, up to numchars visible + * characters. The apparent length skips over nonprinting ansi and + * tags. + * \param p string. + * \param numchars maximum size to report. + * \return apparent length of string. + */ +int +ansi_strnlen(const char *p, size_t numchars) +{ + size_t i = 0; + + if (!p) + return 0; + while (*p && numchars > 0) { + if (*p == ESC_CHAR) { + while ((*p) && (*p != 'm')) { + p++; + i++; + } + } else if (*p == TAG_START) { + while ((*p) && (*p != TAG_END)) { + p++; + i++; + } + } else + numchars--; + i++; + p++; + } + return i; +} + +/** Compare two strings, ignoring all ansi and html markup from a string. + * Is *NOT* locale safe (a la strcoll) + * \param a string to compare to + * \param b Other string + * \return int - 0 is identical, -1 or 1 for difference. + */ +int +ansi_strcmp(const char *astr, const char *bstr) +{ + const char *a, *b; + + for (a = astr, b = bstr; *a && *b;) { + a = skip_leading_ansi(a); + b = skip_leading_ansi(b); + if (*a != *b) + return (*a - *b); + b++; + a++; + } + if (*a) + a = skip_leading_ansi(a); + if (*b) + b = skip_leading_ansi(b); + return (*a - *b); +} + +/** Compare ansi_data for exact equality. + * \param a ansi_data to compare + * \param b other ansi_data + * \return int - 1 is identical, 0 is different + */ +int +ansi_equal(const ansi_data a, const ansi_data b) +{ + return ((a.bits == b.bits) && (a.offbits == b.offbits) && + (a.fore == b.fore) && (a.back == b.back)); +} + +/** Return true if ansi_data contains no ansi values. + * \param a ansi_data to check + * \return int 1 on ansi_null, 0 otherwise + */ +int +ansi_isnull(const ansi_data a) +{ + return ((a.bits == 0) && (a.offbits == 0) && (a.fore == 0) && (a.back == 0)); +} + +/** Strip all ANSI and HTML markup from a string. As a side effect, + * stores the length of the stripped string in a provided address. + * NOTE! Length returned is length *including* the terminating NULL, + * because we usually memcpy the result. + * \param orig string to strip. + * \param s_len address to store length of stripped string, if provided. + * \return pointer to static buffer containing stripped string. + */ +char * +remove_markup(const char *orig, size_t * s_len) +{ + static char buff[BUFFER_LEN]; + char *bp = buff; + const char *q; + size_t len = 0; + + if (!orig) { + if (s_len) + *s_len = 0; + return NULL; + } + + for (q = orig; *q;) { + switch (*q) { + case ESC_CHAR: + /* Skip over ansi */ + while (*q && *q++ != 'm') ; + break; + case TAG_START: + /* Skip over HTML */ + while (*q && *q++ != TAG_END) ; + break; + default: + safe_chr(*q++, buff, &bp); + len++; + } + } + *bp = '\0'; + if (s_len) + *s_len = len + 1; + return buff; +} + +static char ansi_chars[50]; +static int ansi_codes[255]; + +#define BUILD_ANSI(letter,ESCcode) \ +do { \ + ansi_chars[ESCcode] = letter; \ + ansi_codes[(unsigned char) letter] = ESCcode; \ +} while (0) + +void +init_ansi_codes(void) +{ + memset(ansi_chars, 0, sizeof(ansi_chars)); + memset(ansi_codes, 0, sizeof(ansi_codes)); +/* + BUILD_ANSI('n', COL_NORMAL); + BUILD_ANSI('f', COL_FLASH); + BUILD_ANSI('h', COL_HILITE); + BUILD_ANSI('i', COL_INVERT); + BUILD_ANSI('u', COL_UNDERSCORE); +*/ + BUILD_ANSI('x', COL_BLACK); + BUILD_ANSI('X', COL_BLACK + 10); + BUILD_ANSI('r', COL_RED); + BUILD_ANSI('R', COL_RED + 10); + BUILD_ANSI('g', COL_GREEN); + BUILD_ANSI('G', COL_GREEN + 10); + BUILD_ANSI('y', COL_YELLOW); + BUILD_ANSI('Y', COL_YELLOW + 10); + BUILD_ANSI('b', COL_BLUE); + BUILD_ANSI('B', COL_BLUE + 10); + BUILD_ANSI('m', COL_MAGENTA); + BUILD_ANSI('M', COL_MAGENTA + 10); + BUILD_ANSI('c', COL_CYAN); + BUILD_ANSI('C', COL_CYAN + 10); + BUILD_ANSI('w', COL_WHITE); + BUILD_ANSI('W', COL_WHITE + 10); +} + +#undef BUILD_ANSI + +int +write_ansi_data(ansi_data *cur, char *buff, char **bp) +{ + int retval = 0; + retval += safe_chr(TAG_START, buff, bp); + retval += safe_chr(MARKUP_COLOR, buff, bp); + retval += write_ansi_letters(cur, buff, bp); + retval += safe_chr(TAG_END, buff, bp); + return retval; +} + +static int +write_ansi_close(char *buff, char **bp) +{ + int retval = 0; + retval += safe_chr(TAG_START, buff, bp); + retval += safe_chr(MARKUP_COLOR, buff, bp); + retval += safe_chr('/', buff, bp); + retval += safe_chr(TAG_END, buff, bp); + return retval; +} + +static int +write_ansi_letters(const ansi_data *cur, char *buff, char **bp) +{ + int retval = 0; + char *save; + save = *bp; + if (cur->fore == 'n') { + retval += safe_chr(cur->fore, buff, bp); + } else { +#define CBIT_SET(x,y) (x->bits & y) + if (CBIT_SET(cur, CBIT_FLASH)) + retval += safe_chr('f', buff, bp); + if (CBIT_SET(cur, CBIT_HILITE)) + retval += safe_chr('h', buff, bp); + if (CBIT_SET(cur, CBIT_INVERT)) + retval += safe_chr('i', buff, bp); + if (CBIT_SET(cur, CBIT_UNDERSCORE)) + retval += safe_chr('u', buff, bp); +#undef CBIT_SET +#define CBIT_SET(x,y) (x->offbits & y) + if (CBIT_SET(cur, CBIT_FLASH)) + retval += safe_chr('F', buff, bp); + if (CBIT_SET(cur, CBIT_HILITE)) + retval += safe_chr('H', buff, bp); + if (CBIT_SET(cur, CBIT_INVERT)) + retval += safe_chr('I', buff, bp); + if (CBIT_SET(cur, CBIT_UNDERSCORE)) + retval += safe_chr('U', buff, bp); +#undef CBIT_SET + + if (cur->fore) + retval += safe_chr(cur->fore, buff, bp); + if (cur->back) + retval += safe_chr(cur->back, buff, bp); + } + + if (retval) + *bp = save; + return retval; +} + + +void +nest_ansi_data(ansi_data *old, ansi_data *cur) +{ + if (cur->fore != 'n') { + cur->bits |= old->bits; + cur->bits &= ~cur->offbits; + if (!cur->fore) + cur->fore = old->fore; + if (!cur->back) + cur->back = old->back; + } else { + cur->bits = 0; + cur->offbits = 0; + cur->back = 0; + } +} + +/* We need EDGE_UP to return 1 if x has bit set and y doesn't. */ +#define EDGE_UP(x,y,z) ((x.bits & z) != (y->bits & z)) +int +write_raw_ansi_data(ansi_data *old, ansi_data *cur, char *buff, char **bp) +{ + int f = 0; + ansi_data past = *old; + ansi_data pres = *cur; + /* This shouldn't happen */ + if (pres.fore == 'n') { + if (past.bits || (past.fore != 'n') || past.back) { + return safe_str(ANSI_RAW_NORMAL, buff, bp); + } + } + if (pres.fore == 'd') + pres.fore = 0; + if (pres.back == 'D') + pres.back = 0; + + /* Do we *unset* anything in cur? */ + if ((past.bits & ~(pres.bits)) || + (past.fore && !pres.fore) || (past.back && !pres.back)) { + safe_str(ANSI_RAW_NORMAL, buff, bp); + past = ansi_null; + } + + if (past.fore == pres.fore && past.back == pres.back && + past.bits == pres.bits) + return 0; + + if (!(pres.fore || pres.back || pres.bits)) { + if (past.fore != 'n') + return safe_str(ANSI_RAW_NORMAL, buff, bp); + return 0; + } + + safe_str(ANSI_BEGIN, buff, bp); + if (EDGE_UP(past, cur, CBIT_HILITE)) { + if (f++) + safe_chr(';', buff, bp); + safe_integer(COL_HILITE, buff, bp); + } + if (EDGE_UP(past, cur, CBIT_INVERT)) { + if (f++) + safe_chr(';', buff, bp); + safe_integer(COL_INVERT, buff, bp); + } + if (EDGE_UP(past, cur, CBIT_FLASH)) { + if (f++) + safe_chr(';', buff, bp); + safe_integer(COL_FLASH, buff, bp); + } + if (EDGE_UP(past, cur, CBIT_UNDERSCORE)) { + if (f++) + safe_chr(';', buff, bp); + safe_integer(COL_UNDERSCORE, buff, bp); + } + + if (pres.fore && pres.fore != past.fore) { + if (f++) + safe_chr(';', buff, bp); + safe_integer(ansi_codes[(unsigned char) pres.fore], buff, bp); + } + if (pres.back && pres.back != past.back) { + if (f++) + safe_chr(';', buff, bp); + safe_integer(ansi_codes[(unsigned char) pres.back], buff, bp); + } + + return safe_str(ANSI_FINISH, buff, bp); +} + +#undef EDGE_UP + +void +define_ansi_data(ansi_data *store, const char *str) +{ + *store = ansi_null; + + for (; str && *str && (*str != TAG_END); str++) { + switch (*str) { + case 'n': /* normal */ + /* This is explicitly normal, it'll never be colored */ + store->bits = 0; + store->offbits = ~0; + store->fore = 'n'; + store->back = 0; + break; + case 'f': /* flash */ + store->bits |= CBIT_FLASH; + store->offbits &= ~CBIT_FLASH; + break; + case 'h': /* hilite */ + store->bits |= CBIT_HILITE; + store->offbits &= ~CBIT_HILITE; + break; + case 'i': /* inverse */ + store->bits |= CBIT_INVERT; + store->offbits &= ~CBIT_INVERT; + break; + case 'u': /* underscore */ + store->bits |= CBIT_UNDERSCORE; + store->offbits &= ~CBIT_UNDERSCORE; + break; + case 'F': /* flash */ + store->offbits |= CBIT_FLASH; + break; + case 'H': /* hilite */ + store->offbits |= CBIT_HILITE; + break; + case 'I': /* inverse */ + store->offbits |= CBIT_INVERT; + break; + case 'U': /* underscore */ + store->offbits |= CBIT_UNDERSCORE; + break; + case 'b': /* blue fg */ + case 'c': /* cyan fg */ + case 'g': /* green fg */ + case 'm': /* magenta fg */ + case 'r': /* red fg */ + case 'w': /* white fg */ + case 'x': /* black fg */ + case 'y': /* yellow fg */ + case 'd': /* default fg */ + store->fore = *str; + break; + case 'B': /* blue bg */ + case 'C': /* cyan bg */ + case 'G': /* green bg */ + case 'M': /* magenta bg */ + case 'R': /* red bg */ + case 'W': /* white bg */ + case 'X': /* black bg */ + case 'Y': /* yellow bg */ + case 'D': /* default fg */ + store->back = *str; + break; + } + } + store->bits &= ~(store->offbits); +} + +int +read_raw_ansi_data(ansi_data *store, const char *codes) +{ + int curnum; + if (!codes || !store) + return 0; + store->bits = 0; + store->offbits = 0; + store->fore = 0; + store->back = 0; + + /* 'codes' can point at either the ESC_CHAR, + * the '[', or the following byte. */ + + /* Skip to the first ansi number */ + while (*codes && !isdigit((unsigned char) *codes) && *codes != 'm') + codes++; + + while (*codes && (*codes != 'm')) { + curnum = atoi(codes); + if (curnum < 10) { + switch (curnum) { + case COL_HILITE: + store->bits |= CBIT_HILITE; + store->offbits &= ~CBIT_HILITE; + break; + case COL_UNDERSCORE: + store->bits |= CBIT_UNDERSCORE; + store->offbits &= ~CBIT_UNDERSCORE; + break; + case COL_FLASH: + store->bits |= CBIT_FLASH; + store->offbits &= ~CBIT_FLASH; + break; + case COL_INVERT: + store->bits |= CBIT_INVERT; + store->offbits &= ~CBIT_INVERT; + break; + case COL_NORMAL: + store->bits = 0; + store->offbits = ~0; + store->fore = 'n'; + store->back = 0; + break; + } + } else if (curnum < 40) { + store->fore = ansi_chars[curnum]; + } else if (curnum < 50) { + store->back = ansi_chars[curnum]; + } + /* Skip current and find the next ansi number */ + while (*codes && isdigit((unsigned char) *codes)) + codes++; + while (*codes && !isdigit((unsigned char) *codes) && (*codes != 'm')) + codes++; + } + return 1; +} + +/** Return a string pointer past any ansi/html markup at the start. + * \param p a string. + * \return pointer to string after any initial ansi/html markup. + */ + +char * +skip_leading_ansi(const char *p) +{ + if (!p) + return NULL; + while (*p == ESC_CHAR || *p == TAG_START) { + if (*p == ESC_CHAR) { + while (*p && *p != 'm') + p++; + } else { /* TAG_START */ + while (*p && *p != TAG_END) + p++; + } + if (*p) + p++; + } + return (char *) p; + +} + +static char * +parse_tagname(const char *ptr) +{ + static char tagname[BUFFER_LEN]; + char *tag = tagname; + if (!ptr || !*ptr) + return NULL; + while (*ptr && !isspace((unsigned char) *ptr) && *ptr != TAG_END) { + *(tag++) = *(ptr++); + } + *tag = '\0'; + return tagname; +} + +static void +free_markup_info(markup_information *info) +{ + if (info) { + if (info->start_code) { + mush_free(info->start_code, "markup_code"); + info->start_code = NULL; + } + if (info->stop_code) { + mush_free(info->stop_code, "markup_code"); + info->stop_code = NULL; + } + } +} + +/** Convert a string into an ansi_string. + * This takes a string that may contain ansi/html markup codes and + * converts it to an ansi_string structure that separately stores + * the plain string and the markup codes for each character. + * \param source string to parse. + * \return pointer to an ansi_string structure representing the src string. + */ +ansi_string * +parse_ansi_string(const char *source) +{ + return real_parse_ansi_string(source); +} + +/* This does the actual work of parse_ansi_string. */ +ansi_string * +real_parse_ansi_string(const char *source) +{ + ansi_string *data = NULL; + char src[BUFFER_LEN], *sptr; + char tagbuff[BUFFER_LEN]; + char *ptr, *txt; + ansi_data *col; + char *tmp; + char type; + + int pos = 0; + int num = 0; + + int priority = 0; + markup_information *info; + + ansi_data ansistack[BUFFER_LEN]; + int stacktop = 0; + + ansi_data tmpansi; + int oldcodes = 0; + + ansistack[0] = ansi_null; + + if (!source) + return NULL; + + info = NULL; + + sptr = src; + safe_str(source, src, &sptr); + *sptr = '\0'; + + data = mush_malloc(sizeof(ansi_string), "ansi_string"); + if (!data) + return NULL; + + /* Set it to zero */ + memset(data, 0, sizeof(ansi_string)); + + txt = data->text; + col = data->ansi; + + for (ptr = src; *ptr;) { + switch (*ptr) { + case TAG_START: + /* In modern Penn, this is both Pueblo/HTML and color defining code */ + + for (tmp = ptr; *tmp && *tmp != TAG_END; tmp++) ; + if (*tmp) + *tmp = '\0'; + else + tmp--; + ptr++; + /* Now ptr is at TAG_START and tmp is at TAG_END (nulled) */ + + type = *(ptr++); + switch (type) { + case MARKUP_COLOR: + if (!*ptr) + break; + if (oldcodes == 1) { + oldcodes = 0; + stacktop--; + } + /* Start or end tag? */ + if (*ptr != '/') { + define_ansi_data(&tmpansi, ptr); + nest_ansi_data(&(ansistack[stacktop]), &tmpansi); + stacktop++; + ansistack[stacktop] = tmpansi; + } else { + if (*(ptr + 1) == 'a') { + stacktop = 0; /* Endall tag */ + } else { + if (stacktop > 0) + stacktop--; + } + } + break; + case MARKUP_HTML: + if (*ptr && *ptr != '/') { + /* We're at the start tag. */ + info = &(data->markup[data->nmarkups++]); + info->start_code = mush_strdup(ptr, "markup_code"); + snprintf(tagbuff, BUFFER_LEN, "/%s", parse_tagname(ptr)); + info->stop_code = mush_strdup(tagbuff, "markup_code"); + info->type = MARKUP_HTML; + info->start = pos; + info->end = -1; + info->priority = priority++; + } else if (*ptr) { + /* Closing tag */ + for (num = data->nmarkups - 1; num >= 0; num--) { + if (data->markup[num].end < 0 && data->markup[num].stop_code && + strcasecmp(data->markup[num].stop_code, ptr) == 0) { + break; + } + } + if (num >= 0) { + data->markup[num].end = pos; + } else { + /* This is greviously wrong, we can't find the begin tag? + * Consider this a standalone tag with no close tag. */ + info = &(data->markup[data->nmarkups++]); + /* Start code is where we are */ + info->stop_code = mush_strdup(ptr, "markup_code"); + info->type = MARKUP_HTML; + info->priority = priority++; + info->start = -1; + info->end = pos; + } + } + break; + default: + /* This is a broken string. Are we near or at buffer_len? */ + if (ptr - source < BUFFER_LEN - 4) { + /* If we're not, this is broken in more ways than I can think */ + goto broken_string; + } + break; + } + ptr = tmp; + ptr++; + break; + case ESC_CHAR: + /* ESC_CHAR tags shouldn't be used anymore, so hopefully + * we won't get here. + * To parse these, we assume they can't have the new tag-style + * ANSI codes in them, as this should always be true when loading + * from attributes. Assuming that, this code is separate from the + * "actual" tags, creating a single temporary holding space on the + * top of the ansi-stack and playing with the colors there. + */ + for (tmp = ptr; *tmp && *tmp != 'm'; tmp++) ; + + /* Store the "background" colors */ + tmpansi = ansistack[stacktop]; + if (oldcodes == 0) { + oldcodes = 1; + stacktop++; + ansistack[stacktop] = tmpansi; + ansistack[stacktop].offbits = 0; + } + + read_raw_ansi_data(&tmpansi, ptr); + ansistack[stacktop].bits |= tmpansi.bits; + ansistack[stacktop].bits &= ~(tmpansi.offbits); /* ANSI_RAW_NORMAL */ + if (tmpansi.fore) + ansistack[stacktop].fore = tmpansi.fore; + if (tmpansi.back) + ansistack[stacktop].back = tmpansi.back; + + ptr = tmp; + if (*tmp) + ptr++; + break; + default: + col[pos] = ansistack[stacktop]; + txt[pos++] = *(ptr++); + } + } + + txt[pos] = '\0'; + data->len = pos; + + /* For everything left on the stack: + * If it's an HTML code, assume it's a standalone, and leave + * its stop point where it is. */ + for (num = 0; num < data->nmarkups; num++) { + info = &(data->markup[num]); + switch (info->type) { + case MARKUP_HTML: + /* If it's HTML, we treat it as standalone (,
    , etc) + * This is ugly - it's not a "start" but a "stop" */ + if (info->end < 0) { + mush_free(info->stop_code, "markup_code"); + info->stop_code = info->start_code; + info->start_code = NULL; + info->end = info->start; + info->start = -1; + } + break; + } + } + return data; +broken_string: + /* This stinks. We treat this as if it's not pueblo-safe */ + if (data == NULL) + return NULL; + strncpy(data->text, source, BUFFER_LEN); + data->len = strlen(data->text); + for (num = data->nmarkups - 1; num >= 0; num--) { + free_markup_info(&(data->markup[num])); + } + data->nmarkups = 0; + return data; +} + +/** Reverse an ansi string, preserving its ansification. + * This function destructively modifies the ansi_string passed. + * \param as pointer to an ansi string. + */ +void +flip_ansi_string(ansi_string *as) +{ + int i, j; + markup_information *info; + char tmptext; + ansi_data tmpansi; + int mid; + int len = as->len; + + /* Reverse the text */ + mid = len / 2; /* Midpoint */ + for (i = len - 1, j = 0; i >= mid; j++, i--) { + tmptext = as->text[i]; + as->text[i] = as->text[j]; + as->text[j] = tmptext; + + tmpansi = as->ansi[i]; + as->ansi[i] = as->ansi[j]; + as->ansi[j] = tmpansi; + } + + /* Now reverse the html-markup. */ + for (i = as->nmarkups - 1; i >= 0; i--) { + int start, end; + info = &(as->markup[i]); + if (info->start == -1) { + /* Standalones */ + info->end = len - info->end; + } else { + end = len - info->start; + start = len - info->end; + info->start = start; + info->end = end; + } + } +} + +/** Free an ansi_string. + * \param as pointer to ansi_string to free. + */ +void +free_ansi_string(ansi_string *as) +{ + int i; + + if (!as) + return; + + for (i = as->nmarkups - 1; i >= 0; i--) { + free_markup_info(&(as->markup[i])); + } + mush_free(as, "ansi_string"); +} + + +static int +compare_starts(const void *a, const void *b) +{ + markup_information *ai, *bi; + + ai = (markup_information *) a; + bi = (markup_information *) b; + + return ai->start - bi->start; +} + + + +void +optimize_ansi_string(ansi_string *as) +{ + int i, j; + int target = -1; + int len = 0; + + if (!as) + return; + + /* If we've only got 1 or 0, or we've already optimized, do nothing. */ + if (as->nmarkups > 1 && as->optimized == 0) { + /* Sort the markup codes by their start position */ + qsort(as->markup, as->nmarkups, sizeof(markup_information), compare_starts); + + for (i = 0; i < as->nmarkups; i++) { + + /* If end is negative, it's removed or broken. Either way... */ + if (as->markup[i].end < 0) + continue; + + for (j = i + 1; j < as->nmarkups; j++) { + + /* Already removed? */ + if (as->markup[j].end < 0 && as->markup[j].start < 0) + continue; + + /* End if we can't stretch markup[i] any farther */ + if (as->markup[i].end < as->markup[j].start) + break; + + /* If there's an identical code within our bounds, merge it. */ + if (as->markup[i].start_code && as->markup[j].start_code && + (strcmp(as->markup[j].start_code, as->markup[i].start_code) == 0) + ) { + if (as->markup[j].end > as->markup[i].end) + as->markup[i].end = as->markup[j].end; + as->markup[j].start = -1; + as->markup[j].end = -1; + } /* end if_indentical */ + } /* end inner loop */ + } /* end outer loop */ + } + /* end if_optimized */ + j = 0; + + /* Get rid of all removed markups + * "target" is non-negative when we've pegged a destination + * "len" begins counting when we have a target set and we hit a + * block of non-removed markup + * If len is non-zero and we hit a removed markup, shift the block left. + * The end of the removed string is our new target (it's removable anyway) + */ + + for (i = 0; i < as->nmarkups; i++) { + /* Valid tag? */ + if (as->markup[i].end >= 0 && (as->markup[i].start < as->markup[i].end)) { + if (target != -1) + len++; + j++; + } else { + free_markup_info(&(as->markup[i])); + if (len > 0 && target != -1) + memmove(&(as->markup[target]), &(as->markup[i - len]), + len * sizeof(markup_information)); + if (len > 0 || target == -1) { + target = j; + len = 0; + } + } + } + if (len > 0) + memmove(&(as->markup[target]), &(as->markup[i - len]), + len * sizeof(markup_information)); + + as->nmarkups = j; + as->optimized = 1; +} + +/* Copy the start code for a particular markup_info */ +static int +copy_start_code(markup_information *info, char *buff, char **bp) +{ + int retval = 0; + char *save; + save = *bp; + if (info && info->start_code) { + retval += safe_chr(TAG_START, buff, bp); + retval += safe_chr(info->type, buff, bp); + retval += safe_str(info->start_code, buff, bp); + retval += safe_chr(TAG_END, buff, bp); + } + if (retval) + *bp = save; + return retval; +} + +/* Copy the stop code for a particular markup_info */ +static int +copy_stop_code(markup_information *info, char *buff, char **bp) +{ + int retval = 0; + char *save; + save = *bp; + if (info && info->stop_code) { + retval += safe_chr(TAG_START, buff, bp); + retval += safe_chr(MARKUP_HTML, buff, bp); + retval += safe_str(info->stop_code, buff, bp); + retval += safe_chr(TAG_END, buff, bp); + } + if (retval) + *bp = save; + return retval; +} + +#ifdef ANSI_DEBUG +void +inspect_ansi_string(ansi_string *as, dbref who) +{ + markup_information *info; + int count = 0; + int j; + notify_format(who, "Inspecting ansi string"); + notify_format(who, " Text: %s", as->text); + notify_format(who, " Nmarkups: %d", as->nmarkups); + for (j = 0; j < as->nmarkups; j++) { + info = &(as->markup[j]); + if (info->type == MARKUP_HTML) { + notify_format(who, + " %d (%s): (start: %d end: %d) start_code: %s stop_code: %s", + count++, (info->type == MARKUP_HTML ? "html" : "ansi"), + info->start, info->end, info->start_code, info->stop_code); + } + } + notify_format(who, "Inspecting ansi string complete"); +} +#endif + +/** Delete a portion of an ansi string. + * \param as ansi_string to delete from + * \param start start point to remove + * \param size length of string to remove + * \retval 0 success + * \reval 1 failure. + */ + +int +ansi_string_delete(ansi_string *as, int start, int count) +{ + int i; + int end; + markup_information *dm; + + /* Nothing to delete */ + if (start >= as->len || count <= 0) + return 0; + + /* We can't delete from a negative index */ + if (start < 0) { + /* start is negative: this *decreases* count. */ + count += start; + start = 0; + } + + /* We can't delete past the end of our string */ + if ((start + count) > as->len) + count = as->len - start; + + /* Nothing to delete */ + if (count <= 0) + return 0; + + end = start + count; + + dm = as->markup; + + /* Remove or shrink the Pueblo markup on dst */ + for (i = 0; i < as->nmarkups; i++) { + if (dm[i].start >= start && dm[i].end <= end) { + dm[i].start = -1; + dm[i].end = -1; + } + if (dm[i].start >= start) { + dm[i].start -= count; + if (dm[i].start < start) + dm[i].start = start; + } + if (dm[i].end > start) { + dm[i].end -= count; + if (dm[i].end < start) + dm[i].end = start; + } + } + + if (as->nmarkups > 0) + as->optimized = 0; + + /* Shift text over */ + memmove(as->text + start, as->text + end, as->len - end); + memmove(as->ansi + start, as->ansi + end, + (as->len - end) * sizeof(ansi_data)); + as->len -= count; + as->text[as->len] = '\0'; + as->ansi[as->len] = ansi_null; + return 0; +} + +#define copyto(x,y) \ +do { \ + x.type = y.type; \ + x.priority = y.priority; \ + if (y.start_code) x.start_code = mush_strdup(y.start_code,"markup_code"); \ + else (x.start_code = NULL); \ + if (y.stop_code) x.stop_code = mush_strdup(y.stop_code,"markup_code"); \ + else (x.stop_code = NULL); \ +} while (0) + +/** Insert an ansi string into another ansi_string + * with markups kept as straight as possible. + * \param dst ansi_string to insert into. + * \param loc Location to insert into, 0-indexed + * \param src ansi_string to insert + * \retval 0 success + * \retval 1 failure. + */ + +int +ansi_string_insert(ansi_string *dst, int loc, ansi_string *src) +{ + int i, j; + int len; + int retval = 0; + int src_len = src->len; + + markup_information *dm, *sm; + + ansi_data backansi; + + + /* If src->len == 0, we might have only markup. Stand-alones. Ew! */ + if (src->len <= 0 && src->nmarkups <= 0) + return 0; + if (dst->len >= BUFFER_LEN) + return 1; + + if (src_len >= BUFFER_LEN) + src_len = BUFFER_LEN - 1; + if (src_len < 0) + src_len = 0; + + if (loc > dst->len) + loc = dst->len; + if (loc < 0) + loc = 0; + + if (dst->nmarkups > 0 || src->nmarkups > 0) + dst->optimized = 0; + + dm = dst->markup; + sm = src->markup; + + /* shift or widen the Pueblo markup on dst */ + for (i = 0; i < dst->nmarkups; i++) { + if (loc <= dm[i].start) + dm[i].start += src_len; + if (loc < dm[i].end) + dm[i].end += src_len; + } + + /* Copy markup onto the end of dst */ + for (j = 0; j < src->nmarkups; j++) { + + /* It's possible, but not at all easy, to get this much Pueblo markup */ + if (i >= BUFFER_LEN) + break; + + /* Is it a valid tag? */ + if (sm[j].end >= 0 && sm[j].start < sm[j].end && + ((sm[j].start < 0 && sm[j].end <= src_len) + || (sm[j].start < src_len && sm[j].start >= 0))) { + + copyto(dm[i], sm[j]); + + /* If our start is non-negative, start+loc is its position in dm */ + if (sm[j].start >= 0) + dm[i].start = sm[j].start + loc; + else + dm[i].start = -1; + + /* Make sure the end position is within the bounds of its own string */ + if (sm[j].end <= src_len) + dm[i].end = sm[j].end + loc; + else + dm[i].end = src_len + loc; + + i++; + } + } + + for (; i >= BUFFER_LEN; i--) + free_markup_info(&(dm[i])); + dst->nmarkups = i; + + dst->len += src_len; + if (dst->len >= BUFFER_LEN) { + retval = 1; + dst->len = BUFFER_LEN - 1; + } + + len = dst->len - src->len - loc; + + /* Determine what old ansi might stretch across the new text. + * This sets backansi to any ansi values (bits, colors) that + * are continuous across an entire length of text. */ + backansi = ansi_null; + if (0 < loc && loc < dst->len) { + backansi.offbits = dst->ansi[loc - 1].offbits & dst->ansi[loc].offbits; + backansi.bits = dst->ansi[loc - 1].bits & dst->ansi[loc].bits; + if (dst->ansi[loc - 1].fore == dst->ansi[loc].fore) + backansi.fore = dst->ansi[loc].fore; + if (dst->ansi[loc - 1].back == dst->ansi[loc].back) + backansi.back = dst->ansi[loc].back; + } + + /* Shift text over */ + if (0 < len) { + /* The length beyond our insertion that can *actually* be moved. */ + if (loc + src_len + len >= BUFFER_LEN) + len = BUFFER_LEN - loc - src_len - len - 1; + memmove(dst->text + loc + src_len, dst->text + loc, len); + memmove(dst->ansi + loc + src_len, dst->ansi + loc, + len * sizeof(ansi_data)); + } + + + /* Copy text from src */ + if (loc + src_len >= BUFFER_LEN) + src_len = BUFFER_LEN - 1 - loc; + if (src_len > 0) { + memcpy(dst->text + loc, src->text, src_len); + for (i = 0; i < src_len; i++) { + j = loc + i; + dst->ansi[j].back = src->ansi[i].back ? src->ansi[i].back : backansi.back; + dst->ansi[j].fore = src->ansi[i].fore ? src->ansi[i].fore : backansi.fore; + dst->ansi[j].offbits = src->ansi[i].offbits | backansi.offbits; + dst->ansi[j].bits = + ~(dst->ansi[j].offbits) & (src->ansi[i].bits | backansi.bits); + } + } + dst->text[dst->len] = '\0'; + dst->ansi[dst->len] = ansi_null; + return retval; +} + + +/** Replace a portion of an ansi string with + * another ansi string, keeping markups as + * straight as possible. + * \param dst ansi_string to insert into. + * \param loc Location to insert into, 0-indexed + * \param len Length of string inside dst to replace + * \param src ansi_string to insert + * \retval 0 success + * \retval 1 failure. + */ +int +ansi_string_replace(ansi_string *dst, int loc, int len, ansi_string *src) +{ + int i, j; + int end, d_end; + int diff; + int retval = 0; + ansi_data backansi; + markup_information *dm, *sm; + + if (loc < 0) + loc = 0; + + /* Is it really an insert? */ + if (loc >= dst->len || len <= 0) + return ansi_string_insert(dst, loc, src); + + /* Is it really a delete? */ + if (src->len <= 0) + return ansi_string_delete(dst, loc, len); + + /* We can't delete past the end of our string. */ + if ((len + loc) > dst->len) + len = dst->len - loc; + + end = loc + len; /* End of the removed section */ + d_end = loc + src->len; /* End of the new string within the dst string */ + diff = src->len - len; /* Total change in length */ + + if (diff > 0 && dst->len >= BUFFER_LEN) + return 1; + + dst->optimized = 0; + + dm = dst->markup; + sm = src->markup; + + /* Modify, remove, stretch, and mangle Pueblo markup */ + for (i = 0; i < dst->nmarkups; i++) { + + /* If it doesn't cross into the replaced part, leave as is */ + if (dm[i].end <= loc) + continue; + + /* Debatable: If it surrounds the replaced part exactly, try + * to keep it, stretching it to wrap around the replacement. */ + if (loc <= dm[i].start && dm[i].end <= end) { + /* If the locations match, stretch it, otherwise overwrite it. */ + if (dm[i].start == loc && dm[i].end == end) { + dm[i].end = loc + src->len; + } else { + dm[i].start = -1; + dm[i].end = -1; + } + continue; + } + + /* Shift the beginning if necessary */ + if (loc < dm[i].start) { + /* If we're beyond the markup, just shift start. */ + if (end < dm[i].start) { + dm[i].start += diff; + } else { + /* Otherwise it's inside; push it to the right of the new markup. */ + dm[i].start = loc + src->len; + } + if (dm[i].start > BUFFER_LEN) { + dm[i].start = -1; + dm[i].end = -1; + } + } + + /* If this markup ends before the new one, squish it. */ + if (dm[i].end < end) { + dm[i].end = (dm[i].start >= 0) ? loc : -1; /* Or erase stand-alones */ + } else { + dm[i].end += diff; /* Otherwise, shift it. */ + if (dm[i].end > BUFFER_LEN) + dm[i].end = BUFFER_LEN; + } + + } + + /* Copy markup. Code taken from ansi_string_insert. */ + for (j = 0; j < src->nmarkups; j++) { + + /* It's possible, but not at all easy, to get this much pueblo markup */ + if (i >= BUFFER_LEN) + break; + + /* Is it a valid tag? */ + if (sm[j].end >= 0 && sm[j].start < sm[j].end && + ((sm[j].start < 0 && sm[j].end <= src->len) + || (sm[j].start < src->len && sm[j].start >= 0))) { + + copyto(dm[i], sm[j]); + + /* If our start is non-negative, start+loc is its position in dm */ + if (sm[j].start >= 0) + dm[i].start = sm[j].start + loc; + else + dm[i].start = -1; + + /* Make sure the end position is within the bounds of its own string */ + if (sm[j].end <= src->len) + dm[i].end = sm[j].end + loc; + else + dm[i].end = src->len + loc; + + i++; + } + } + + for (; i >= BUFFER_LEN; i--) + free_markup_info(&(dm[i])); + dst->nmarkups = i; + + /* length of original string after replace bits */ + len = dst->len - end; + + dst->len += diff; + if (dst->len >= BUFFER_LEN) { + retval = 1; + dst->len = BUFFER_LEN - 1; + } + + /* Determine what old ansi might stretch across the new text. + * This sets backansi to any ansi values (bits, colors) that + * are continuous across an entire length of text. + */ + backansi = dst->ansi[loc]; + for (i = loc; i < end && !ansi_isnull(backansi); i++) { + backansi.offbits &= dst->ansi[i].offbits; + backansi.bits &= dst->ansi[i].bits; + if (backansi.fore != dst->ansi[i].fore) + backansi.fore = 0; + if (backansi.back != dst->ansi[i].back) + backansi.back = 0; + } + + /* Shift text over */ + if (diff != 0) { + if (d_end + len >= BUFFER_LEN) + len = BUFFER_LEN - (1 + d_end); + if (len > 0) { + memmove(dst->text + d_end, dst->text + end, len); + memmove(dst->ansi + d_end, dst->ansi + end, len * sizeof(ansi_data)); + } + } + + /* Copy text from src */ + len = src->len; + if (loc + len >= BUFFER_LEN) + len = BUFFER_LEN - loc - 1; + if (len > 0) { + memcpy(dst->text + loc, src->text, len); + for (i = 0; i < len; i++) { + j = loc + i; + dst->ansi[j].back = src->ansi[i].back ? src->ansi[i].back : backansi.back; + dst->ansi[j].fore = src->ansi[i].fore ? src->ansi[i].fore : backansi.fore; + dst->ansi[j].offbits = src->ansi[i].offbits | backansi.offbits; + dst->ansi[j].bits = + ~(dst->ansi[j].offbits) & (src->ansi[i].bits | backansi.bits); + } + } + dst->text[dst->len] = '\0'; + dst->ansi[dst->len] = ansi_null; + return retval; +} + + +/** Scrambles an ansi_string, returning a pointer to the new string. + * \param as ansi_string to scramble. + */ +ansi_string * +scramble_ansi_string(ansi_string *as) +{ + int i, j, k; + int pos[BUFFER_LEN]; + markup_information *dm; + ansi_string *tmp = NULL; + + if (!as) + return NULL; + + optimize_ansi_string(as); + + tmp = mush_malloc(sizeof(ansi_string), "ansi_string"); + if (!tmp) + return NULL; + + memset(tmp, 0, sizeof(ansi_string)); + + /* Scramble the text */ + tmp->len = as->len; + + for (i = 0; i < as->len; i++) + pos[i] = i; + + for (i = 0; i < as->len; i++) { + j = get_random_long(0, as->len - 1); + k = pos[i]; + pos[i] = pos[j]; + pos[j] = k; + } + + /* The old scramble did new[i] = old[pos[i]], + * but handling markup tags is easier if we do it this way. */ + /* Scramble the text and ansi... */ + for (i = 0; i < as->len; i++) { + tmp->text[pos[i]] = as->text[i]; + tmp->ansi[pos[i]] = as->ansi[i]; + } + + /* Scramble the Pueblo markup */ + dm = tmp->markup; + if (as->nmarkups > 0) + tmp->optimized = 0; + + /* Copy the standalones (tags with -1 for start) */ + for (i = 0; i < as->nmarkups && as->markup[i].start == -1; i++) { + copyto(dm[i], as->markup[i]); + dm[i].end = pos[i]; + } + + /* Copy the rest */ + j = i; + for (; i < as->nmarkups; i++) { + for (k = as->markup[i].start; k < as->markup[i].end; k++) { + copyto(dm[j], as->markup[i]); + dm[j].start = pos[k]; + dm[j].end = dm[j].start + 1; + j++; + if (j >= BUFFER_LEN) { + optimize_ansi_string(tmp); + tmp->optimized = 0; + j = tmp->nmarkups; + if (j >= BUFFER_LEN) + return tmp; + } + } + } + tmp->nmarkups = j; + optimize_ansi_string(tmp); + return tmp; +} + +#undef copyto + +/** Safely append an ansi_string into a buffer as a real string, + * \param as pointer to ansi_string to append. + * \param start position in as to start copying from. + * \param len length in characters to copy from as. + * \param buff buffer to insert into. + * \param bp pointer to pointer to insertion point of buff. + * \retval 0 success. + * \retval 1 failure. + */ +int +safe_ansi_string(ansi_string *as, int start, int len, char *buff, char **bp) +{ + int i, j; + int cur; + markup_information *info; + int nextstart, nextend, next; + int end = start + len; + int retval = 0; + ansi_data curansi; + + if (!as) + return 0; + + optimize_ansi_string(as); + + if (len <= 0) + return 0; + if (as->len > BUFFER_LEN) + as->len = BUFFER_LEN; + if (start >= as->len) + return 0; + if (end > as->len) + end = as->len; + + /* Standalones (Stop codes with -1 for start) */ + for (j = 0; j < as->nmarkups; j++) { + info = &(as->markup[j]); + if (info->start != -1) + break; /* No more standalone tags to copy */ + if (info->stop_code && info->end == start) + retval += safe_str(info->stop_code, buff, bp); + } + + /* Now, start codes of everything that impacts us. */ + for (; j < as->nmarkups; j++) { + info = &(as->markup[j]); + if (info->start > start) + break; /* No more tags to copy. */ + if (info->end > start) + retval += copy_start_code(info, buff, bp); + } + + /* Find the next changes--new tags, or a prior tag ending. */ + i = start; + nextend = BUFFER_LEN + 1; + + /* If there is another start, it's our next one; we have a sorted list. */ + if (j < as->nmarkups) + nextstart = as->markup[j].start; + else + nextstart = BUFFER_LEN + 1; + + /* To find the next END is harder, since it isn't sorted... */ + /* Scan forward. Stop once we find a tag with a start beyond + * this one's end. Anything beyond that can't be the nextend, + * so we'll backtrack from there. */ + if (as->nmarkups > 0) { + cur = j; + if (cur >= as->nmarkups) + cur--; + info = &(as->markup[cur]); + while (cur < as->nmarkups && as->markup[cur].start < info->end) + cur++; + cur--; + if (info->end > as->markup[cur].start) { + for (; cur >= 0; cur--) { + if (as->markup[cur].end > i && as->markup[cur].end < nextend) + nextend = as->markup[cur].end; + } + } + } + + next = (nextend < nextstart) ? nextend : nextstart; + + if (end < next) + next = end; + + curansi = as->ansi[start]; + if (!ansi_isnull(curansi)) + write_ansi_data(&curansi, buff, bp); + /* If there's any text/ansi between start and next, print it */ + for (i = start; i < next && i < as->len; i++) { + if (as->text[i]) { + if (!ansi_equal(curansi, as->ansi[i])) { + if (!ansi_isnull(curansi)) + write_ansi_close(buff, bp); + curansi = as->ansi[i]; + if (!ansi_isnull(curansi)) + write_ansi_data(&curansi, buff, bp); + } + safe_chr(as->text[i], buff, bp); + } + } + + cur = j; /* Our current markup */ + i = next; /* Our current position */ + + /* Basically the same thing as above, in loop form. */ + while (i < end) { + + if (i >= nextend) { + nextend = BUFFER_LEN + 2; + j = cur; + /* Find the last markup that could possibly have a relevant end code */ + while (j < as->nmarkups && as->markup[j].start < as->markup[cur].end) + j++; + j--; + /* We MUST have markup if we're here, so no nmarkup > 0 check. */ + /* Print relevant stop codes, and find our nextend */ + for (; j >= 0; j--) { + info = &(as->markup[j]); + if (info->end >= i) { + if (info->end == i) + retval += copy_stop_code(info, buff, bp); + else if (info->end < nextend) + nextend = info->end; + } + } + } + + if (i >= nextstart) { + /* Print out all the relevant start codes */ + for (; cur < as->nmarkups && as->markup[cur].start == i; cur++) + retval += copy_start_code(&(as->markup[cur]), buff, bp); + if (cur < as->nmarkups) + nextstart = as->markup[cur].start; + else + nextstart = BUFFER_LEN + 2; + } + + next = (nextend < nextstart) ? nextend : nextstart; + if (end < next) + next = end; + + + for (; i < next && i < as->len; i++) { + if (as->text[i]) { + if (!ansi_equal(curansi, as->ansi[i])) { + if (!ansi_isnull(curansi)) + write_ansi_close(buff, bp); + curansi = as->ansi[i]; + if (!ansi_isnull(curansi)) + write_ansi_data(&curansi, buff, bp); + } + safe_chr(as->text[i], buff, bp); + } + } + } + + /* Now, find all things that end for us */ + if (as->nmarkups > 0) { + j = cur; + while (cur < as->nmarkups && as->markup[j].end > as->markup[cur].start) + cur++; + cur--; + for (; cur >= 0; cur--) { + info = &(as->markup[cur]); + if (info->start < i && info->end >= i) + retval += copy_stop_code(info, buff, bp); + } + } + + if (!retval && !ansi_isnull(curansi)) + retval += write_ansi_close(buff, bp); + return retval; +} + +/* Following functions are used for + * decompose_str() + */ + +extern char escaped_chars[UCHAR_MAX + 1]; + +static int +escape_marked_str(char **str, char *buff, char **bp) +{ + unsigned char *in; + int retval = 0; + int dospace = 1; + int spaces = 0; + int i; + + if (!str || !*str || !**str) + return 0; + in = (unsigned char *) *str; + for (; *in && *in != ESC_CHAR && *in != TAG_START; in++) { + if (*in == ' ') { + spaces++; + } else { + if (spaces) { + if (spaces >= 5) { + retval += safe_str("[space(", buff, bp); + retval += safe_number(spaces, buff, bp); + retval += safe_str(")]", buff, bp); + } else { + if (dospace) { + spaces--; + retval += safe_str("%b", buff, bp); + } + while (spaces) { + retval += safe_chr(' ', buff, bp); + if (--spaces) { + --spaces; + retval += safe_str("%b", buff, bp); + } + } + } + } + spaces = 0; + dospace = 0; + switch (*in) { + case '\n': + retval += safe_str("%r", buff, bp); + break; + case '\t': + retval += safe_str("%t", buff, bp); + break; + case BEEP_CHAR: + for (i = 1; *(in + 1) == BEEP_CHAR && i < 5; in++, i++) ; + retval += safe_format(buff, bp, "[beep(%d)]", i); + break; + default: + if (escaped_chars[*in]) + retval += safe_chr('\\', buff, bp); + retval += safe_chr(*in, buff, bp); + break; + } + } + } + if (spaces) { + if (spaces >= 5) { + retval += safe_str("[space(", buff, bp); + retval += safe_number(spaces, buff, bp); + retval += safe_str(")]", buff, bp); + } else { + spaces--; /* This is for the final %b space */ + if (spaces && dospace) { + spaces--; + retval += safe_str("%b", buff, bp); + } + while (spaces) { + safe_chr(' ', buff, bp); + if (--spaces) { + --spaces; + retval += safe_str("%b", buff, bp); + } + } + retval += safe_str("%b", buff, bp); + } + } + *str = (char *) in; + return retval; +} + +/* Does the work of decompose_str, which is found in look.c. + * Even handles ANSI and Pueblo, which is why it's so ugly. + * Code based off of real_parse_ansi_string, not safe_ansi_string. + */ +int +real_decompose_str(char *orig, char *buff, char **bp) +{ + int i; + char *str = orig; + char *tmp; + char *pstr; + char type; + + ansi_data ansistack[BUFFER_LEN]; + ansi_data oldansi; + ansi_data tmpansi; + int ansitop = 0; + int ansiheight = 0; + int howmanyopen = 0; + int oldcodes = 0; + + char *pueblostack[BUFFER_LEN]; + char tagbuff[BUFFER_LEN]; + int pueblotop = -1; + + int retval = 0; + + ansistack[0] = ansi_null; + + if (!str || !*str) + return 0; + + retval += escape_marked_str(&str, buff, bp); + + while (str && *str && *str != '\0') { + oldansi = ansistack[ansitop]; + ansiheight = ansitop; + while (*str == TAG_START || *str == ESC_CHAR) { + switch (*str) { + case TAG_START: + for (tmp = str; *tmp && *tmp != TAG_END; tmp++) ; + if (*tmp) { + *tmp = '\0'; + } else { + tmp--; + } + str++; + type = *(str++); + switch (type) { + case MARKUP_COLOR: + if (!*str) + break; + if (oldcodes == 1) { + ansitop--; + oldcodes = 0; + } + /* Start or end tag? */ + if (*str != '/') { + define_ansi_data(&tmpansi, str); + nest_ansi_data(&(ansistack[ansitop]), &tmpansi); + ansitop++; + ansistack[ansitop] = tmpansi; + } else { + if (*(str + 1) == 'a') { + ansitop = 0; + } else { + if (ansitop > 0) { + ansitop--; + } + } + } + break; + case MARKUP_HTML: + if (!*str) + break; + if (*str != '/') { + pueblotop++; + snprintf(tagbuff, BUFFER_LEN, "%s", parse_tagname(str)); + pueblostack[pueblotop] = mush_strdup(tagbuff, "markup_code"); + + retval += safe_str("[tag(", buff, bp); + retval += safe_str(tagbuff, buff, bp); + str += strlen(tagbuff); + if (str && *str) { + while (str && str != tmp) { + str++; + pstr = strchr(str, '='); + if (pstr) { + *pstr = '\0'; + retval += safe_chr(',', buff, bp); + retval += safe_str(str, buff, bp); + retval += safe_chr('=', buff, bp); + str = pstr + 1; + pstr = strchr(str, '\"'); + + retval += safe_chr('\"', buff, bp); + if (str == pstr) { + str++; + pstr = strchr(str, '\"'); + } else { + pstr = strchr(str, ' '); + } + + if (!pstr) + pstr = tmp; + + *pstr = '\0'; + retval += safe_str(str, buff, bp); + retval += safe_chr('\"', buff, bp); + str = pstr; + } else { + safe_str(str, buff, bp); + break; + } + } + } + retval += safe_str(")]", buff, bp); + + } else { + if (pueblotop > -1) { + i = (*(str + 1) == 'a') ? 0 : pueblotop; + for (i--; pueblotop > i; pueblotop--) { + retval += safe_str("[endtag(", buff, bp); + retval += safe_str(pueblostack[pueblotop], buff, bp); + retval += safe_str(")]", buff, bp); + mush_free(pueblostack[pueblotop], "markup_code"); + } + } + } + break; + } + tmp++; + str = tmp; + break; + case ESC_CHAR: + /* It SHOULD be impossible to get here... */ + for (tmp = str; *tmp && *tmp != 'm'; tmp++) ; + + /* Store the "background" colors */ + tmpansi = ansistack[ansitop]; + if (oldcodes == 0) { + oldcodes = 1; + ansitop++; + ansistack[ansitop] = tmpansi; + ansistack[ansitop].offbits = 0; + } + + read_raw_ansi_data(&tmpansi, str); + ansistack[ansitop].bits |= tmpansi.bits; + ansistack[ansitop].bits &= ~(tmpansi.offbits); /* ANSI_RAW_NORMAL */ + if (tmpansi.fore) + ansistack[ansitop].fore = tmpansi.fore; + if (tmpansi.back) + ansistack[ansitop].back = tmpansi.back; + + str = tmp; + if (*tmp) + str++; + break; + } + } + + /* Handle ANSI/Text */ + tmpansi = ansistack[ansitop]; + if (ansitop > 0 || ansiheight > 0) { + /* Close existing tags as necessary to cleanly open the next. */ + /* oldansi = ansistack[ansiheight]; */ + if (!ansi_equal(oldansi, tmpansi)) { + while (ansiheight > 0) { + if (howmanyopen > 0) { + howmanyopen--; + retval += safe_str(")]", buff, bp); + } + ansiheight--; + } + } + if (!ansi_isnull(tmpansi) && !ansi_equal(oldansi, tmpansi)) { + retval += safe_str("[ansi(", buff, bp); + retval += write_ansi_letters(&tmpansi, buff, bp); + retval += safe_chr(',', buff, bp); + howmanyopen++; + } + } + retval += escape_marked_str(&str, buff, bp); + } + + for (; howmanyopen > 0; howmanyopen--) + retval += safe_str(")]", buff, bp); + for (; pueblotop > -1; pueblotop--) { + retval += safe_str("[endtag(", buff, bp); + retval += safe_str(pueblostack[pueblotop], buff, bp); + retval += safe_str(")]", buff, bp); + } + + return retval; +} + +/** Our version of pcre_copy_substring, with ansi-safeness. + * \param as the ansi_string whose .text value was matched against. + * \param ovector the offset vectors + * \param stringcount the number of subpatterns + * \param stringnumber the number of the desired subpattern + * \param buff buffer to copy the subpattern to + * \param bp pointer to the end of buffer + * \return size of subpattern, or -1 if unknown pattern + */ +int +ansi_pcre_copy_substring(ansi_string *as, int *ovector, + int stringcount, int stringnumber, + int nonempty, char *buff, char **bp) +{ + int yield; + if (stringnumber < 0 || stringnumber >= stringcount) + return -1; + stringnumber *= 2; + yield = ovector[stringnumber + 1] - ovector[stringnumber]; + if (!nonempty || yield) { + safe_ansi_string(as, ovector[stringnumber], yield, buff, bp); + **bp = '\0'; + } + return yield; +} + + +/** Our version of pcre_copy_named_substring, with ansi-safeness. + * \param code the pcre compiled code + * \param as the ansi_string whose .text value was matched against. + * \param ovector the offset vectors + * \param stringcount the number of subpatterns + * \param stringname the name of the desired subpattern + * \param buff buffer to copy the subpattern to + * \param bp pointer to the end of buffer + * \return size of subpattern, or -1 if unknown pattern + */ +int +ansi_pcre_copy_named_substring(const pcre * code, ansi_string *as, + int *ovector, int stringcount, + const char *stringname, int ne, + char *buff, char **bp) +{ + int n = pcre_get_stringnumber(code, stringname); + if (n <= 0) + return -1; + return ansi_pcre_copy_substring(as, ovector, stringcount, n, ne, buff, bp); +} + +/** Safely add a tag into a buffer. + * If we support pueblo, this function adds the tag start token, + * the tag, and the tag end token. If not, it does nothing. + * If we can't fit the tag in, we don't put any of it in. + * \param a_tag the html tag to add. + * \param buf the buffer to append to. + * \param bp pointer to address in buf to insert. + * \retval 0, successfully added. + * \retval 1, tag wouldn't fit in buffer. + */ +static int +safe_markup(char const *a_tag, char *buf, char **bp, char type) +{ + int result = 0; + char *save = buf; + result = safe_chr(TAG_START, buf, bp); + result = safe_chr(type, buf, bp); + result = safe_str(a_tag, buf, bp); + result = safe_chr(TAG_END, buf, bp); + /* If it didn't all fit, rewind. */ + if (result) + *bp = save; + return result; +} + +int +safe_tag(char const *a_tag, char *buff, char **bp) +{ + if (SUPPORT_PUEBLO) + return safe_markup(a_tag, buff, bp, MARKUP_HTML); + return 0; +} + +/** Safely add a closing tag into a buffer. + * If we support pueblo, this function adds the tag start token, + * a slash, the tag, and the tag end token. If not, it does nothing. + * If we can't fit the tag in, we don't put any of it in. + * \param a_tag the html tag to add. + * \param buf the buffer to append to. + * \param bp pointer to address in buf to insert. + * \retval 0, successfully added. + * \retval 1, tag wouldn't fit in buffer. + */ +static int +safe_markup_cancel(char const *a_tag, char *buf, char **bp, char type) +{ + int result = 0; + char *save = buf; + result = safe_chr(TAG_START, buf, bp); + result = safe_chr(type, buf, bp); + result = safe_chr('/', buf, bp); + result = safe_str(a_tag, buf, bp); + result = safe_chr(TAG_END, buf, bp); + /* If it didn't all fit, rewind. */ + if (result) + *bp = save; + return result; +} + +int +safe_tag_cancel(char const *a_tag, char *buf, char **bp) +{ + if (SUPPORT_PUEBLO) + return safe_markup_cancel(a_tag, buf, bp, MARKUP_HTML); + return 0; +} + +/** Safely add a tag, some text, and a matching closing tag into a buffer. + * If we can't fit the stuff, we don't put any of it in. + * \param a_tag the html tag to add. + * \param params tag parameters. + * \param data the text to wrap the tag around. + * \param buf the buffer to append to. + * \param bp pointer to address in buf to insert. + * \param player the player involved in all this, or NOTHING if internal. + * \retval 0, successfully added. + * \retval 1, tagged text wouldn't fit in buffer. + */ +int +safe_tag_wrap(char const *a_tag, char const *params, + char const *data, char *buf, char **bp, dbref player) +{ + int result = 0; + char *save = buf; + if (SUPPORT_PUEBLO) { + result = safe_chr(TAG_START, buf, bp); + result = safe_chr(MARKUP_HTML, buf, bp); + result = safe_str(a_tag, buf, bp); + if (params && *params && ok_tag_attribute(player, params)) { + result = safe_chr(' ', buf, bp); + result = safe_str(params, buf, bp); + } + result = safe_chr(TAG_END, buf, bp); + } + result = safe_str(data, buf, bp); + if (SUPPORT_PUEBLO) { + result = safe_tag_cancel(a_tag, buf, bp); + } + /* If it didn't all fit, rewind. */ + if (result) + *bp = save; + return result; +} diff --git a/src/match.c b/src/match.c index b899035..bc6cef9 100644 --- a/src/match.c +++ b/src/match.c @@ -58,7 +58,7 @@ static dbref match_result_internal (dbref who, const char *name, int type, long flags); static dbref simple_matches(dbref who, const char *name, long flags); -static int parse_english(const char **name, long *flags); +static int parse_english(char **name, long *flags); static dbref match_me(const dbref who, const char *name); static dbref match_here(const dbref who, const char *name); /** Convenience alias for parse_objid */ @@ -226,18 +226,21 @@ MATCH_FUNC_PROTO(match_container); MATCH_FUNC_PROTO(match_list); static dbref -match_result_internal(dbref who, const char *name, int type, long flags) +match_result_internal(dbref who, const char *xname, int type, long flags) { dbref match = NOTHING, last_match = NOTHING, exact_match = NOTHING; int exact_matches_to_go, matches_to_go; int matchnum = 0; int result; + char *name, *sname; /* The quick ones that can never be ambiguous */ - match = simple_matches(who, name, flags); + match = simple_matches(who, xname, flags); if (GoodObject(match)) return match; + sname = name = mush_strdup(xname, "mri.string"); + /* Check for adjective phrases */ matchnum = parse_english(&name, &flags); @@ -295,6 +298,7 @@ finished: /* Handle noisy_match_result */ if (flags & MAT_NOISY) { + mush_free(sname, "mri.string"); switch (match) { case NOTHING: notify(who, T("I can't see that here.")); @@ -306,6 +310,7 @@ finished: return match; } } + mush_free(sname, "mri.string"); return match; } @@ -373,10 +378,10 @@ mat_near: * are restrictions */ static int -parse_english(const char **name, long *flags) +parse_english(char **name, long *flags) { int saveflags = *flags; - const char *savename = *name; + char *savename = *name; char *mname; char *e; int count = 0; diff --git a/src/memcheck.c b/src/memcheck.c index 70d5e02..b052f51 100644 --- a/src/memcheck.c +++ b/src/memcheck.c @@ -24,15 +24,20 @@ typedef struct mem_check MEM; +/* Length of longest check name */ +#define REF_NAME_LEN 64 + /** A linked list for storing memory allocation counts */ struct mem_check { int ref_count; /**< Number of allocations of this type. */ MEM *next; /**< Pointer to next in linked list. */ - char ref_name[BUFFER_LEN]; /**< Name of this allocation type. */ + char ref_name[REF_NAME_LEN]; /**< Name of this allocation type. */ }; static MEM *my_check = NULL; +slab *memcheck_slab = NULL; + /*** WARNING! DO NOT USE strcasecoll IN THESE FUNCTIONS OR YOU'LL CREATE *** AN INFINITE LOOP. DANGER, WILL ROBINSON! ***/ @@ -44,14 +49,13 @@ void add_check(const char *ref) { MEM *loop, *newcheck, *prev = NULL; - size_t reflen; int cmp; if (!options.mem_check) return; for (loop = my_check; loop; loop = loop->next) { - cmp = strcasecmp(ref, loop->ref_name); + cmp = strcmp(ref, loop->ref_name); if (cmp == 0) { loop->ref_count++; return; @@ -59,9 +63,11 @@ add_check(const char *ref) break; prev = loop; } - reflen = strlen(ref) + 1; - newcheck = (MEM *) malloc(sizeof(MEM) - BUFFER_LEN + reflen); - memcpy(newcheck->ref_name, ref, reflen); + if (!memcheck_slab) + memcheck_slab = slab_create("mem check references", sizeof(MEM)); + + newcheck = slab_malloc(memcheck_slab, prev); + mush_strncpy(newcheck->ref_name, ref, REF_NAME_LEN); newcheck->ref_count = 1; newcheck->next = loop; if (prev) @@ -75,7 +81,7 @@ add_check(const char *ref) * \param ref type of allocation to remove. */ void -del_check(const char *ref) +del_check(const char *ref, const char *filename, int line) { MEM *loop, *prev = NULL; int cmp; @@ -84,24 +90,23 @@ del_check(const char *ref) return; for (loop = my_check; loop; loop = loop->next) { - cmp = strcasecmp(ref, loop->ref_name); + cmp = strcmp(ref, loop->ref_name); if (cmp == 0) { loop->ref_count--; - if (!loop->ref_count) { - if (!prev) - my_check = loop->next; - else - prev->next = loop->next; - free(loop); - } + if (loop->ref_count < 0) + do_rawlog(LT_TRACE, + T + ("ERROR: Deleting a check with a negative count: %s (At %s:%d)"), + ref, filename, line); return; - } else if (cmp < 0) + } else if (cmp < 0) { + do_rawlog(LT_TRACE, + T("ERROR: Deleting a non-existant check: %s (At %s:%d)"), + ref, filename, line); break; + } prev = loop; } - do_rawlog(LT_CHECK, - T("ERROR: Tried deleting a check that was never added! :%s\n"), - ref); } /** List allocations. @@ -115,7 +120,8 @@ list_mem_check(dbref player) if (!options.mem_check) return; for (loop = my_check; loop; loop = loop->next) { - notify_format(player, "%s : %d", loop->ref_name, loop->ref_count); + if (loop->ref_count != 0) + notify_format(player, "%s : %d", loop->ref_name, loop->ref_count); } } @@ -128,9 +134,9 @@ log_mem_check(void) if (!options.mem_check) return; - do_rawlog(LT_CHECK, "MEMCHECK dump starts"); + do_rawlog(LT_TRACE, "MEMCHECK dump starts"); for (loop = my_check; loop; loop = loop->next) { - do_rawlog(LT_CHECK, "%s : %d", loop->ref_name, loop->ref_count); + do_rawlog(LT_TRACE, "%s : %d", loop->ref_name, loop->ref_count); } - do_rawlog(LT_CHECK, "MEMCHECK dump ends"); + do_rawlog(LT_TRACE, "MEMCHECK dump ends"); } diff --git a/src/modules.c b/src/modules.c index b805816..ba63447 100644 --- a/src/modules.c +++ b/src/modules.c @@ -7,6 +7,8 @@ #include #include #include +#include +#include "config.h" #include "conf.h" #include "externs.h" diff --git a/src/move.c b/src/move.c index ca06add..3333eff 100644 --- a/src/move.c +++ b/src/move.c @@ -542,9 +542,13 @@ do_get(dbref player, const char *what) if (match_result(player, what, TYPE_THING, match_flags) == NOTHING) { if (POSSESSIVE_GET) { dbref box; - const char *boxname = what; + const char *boxname; + char objnamebuf[BUFFER_LEN], *objname; + boxname = what; + strcpy(objnamebuf, what); + objname = objnamebuf; /* take care of possessive get (stealing) */ - box = parse_match_possessor(player, &what); + box = parse_match_possessor(player, &objname); if (box == NOTHING) { notify(player, T("I don't see that here.")); return; @@ -552,7 +556,7 @@ do_get(dbref player, const char *what) notify_format(player, T("I can't tell which %s."), boxname); return; } - thing = match_result(box, what, NOTYPE, MAT_POSSESSION); + thing = match_result(box, objname, NOTYPE, MAT_POSSESSION); if (thing == NOTHING) { notify(player, T("I don't see that here.")); return; diff --git a/src/mushlua.i b/src/mushlua.i index 0e68960..d1894e4 100644 --- a/src/mushlua.i +++ b/src/mushlua.i @@ -1,4 +1,10 @@ %module mush %{ +#include +#include +#include +#include +#include "config.h" + #include "conf.h" #include "externs.h" #include "dbdefs.h" diff --git a/src/mymalloc.c b/src/mymalloc.c index 63f0901..bfb7857 100644 --- a/src/mymalloc.c +++ b/src/mymalloc.c @@ -3,13 +3,50 @@ * * \brief Malloc wrapper file. * - * A wrapper for the various malloc package options. See options.h - * for descriptions of each. - * Each package's source code must include config.h, mymalloc.h, - * and confmagic.h. + * Three things in this file: + * + * -# It includes the body of csrimalloc.c if using a MALLOC_PACKAGE + * of 2 or 3. + * + * -# It has the mush_FOO() wrapper functions for + * malloc()/calloc()/realloc()/free(). These are used to keep + * track of reference counts when the mem_check config option is + * turned on in mush.cnf. Use them instead of plain + * malloc()/free()/etc. + * + * -# It has the slab allocator. The slab allocator should be used + * for small, frequently allocated fixed-size objects. (Structs, + * but not strings, basically), to cut down on system malloc + * overhead. Each time you allocate an object, a bit more space + * than what you requested is used -- there are some bytes before + * or after (Or both) what you can use that the malloc system uses + * to keep track of important things. With lots of small objects, + * this adds to a lot of bytes. A slab allocator knows that it + * will only be dealing with objects of a fixed size, so it can be + * more intelligent but less general-purpose and use a lot less + * overhead. + * */ #include "config.h" +#include +#include +#include +#include +#if defined(MALLOC_PACKAGE) && (MALLOC_PACKAGE == 0) +#ifdef HAVE_UNISTD_H +#include +#endif +#endif /* MALLOC_PACKAGE */ +#ifdef WIN32 +#include +#endif #include "options.h" +#include "conf.h" +#include "dbdefs.h" +#include "log.h" +#include "externs.h" +#include "getpgsiz.h" +#include "mymalloc.h" #include "confmagic.h" /* An undefined or illegal MALLOC_PACKAGE is treated as system @@ -20,3 +57,560 @@ #elif (MALLOC_PACKAGE == 2) #include "csrimalloc.c" #endif + + +/** A malloc wrapper that tracks type of allocation. + * This should be used in preference to malloc() when possible, + * to enable memory leak tracing with MEM_CHECK. + * \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_rawlog(LT_TRACE, "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_TRACE, "mush_calloc failed to allocate %lu bytes for %s", + (unsigned long) (size * count), check); + add_check(check); + return ptr; +} + +/** A realloc wrapper that tracks type of allocation. + * Use in preference to realloc() when possible to enable + * memory leak checking. + * \param ptr pointer to resize + * \param newsize what to resize it to + * \param check string to label with + * \param filename file name it was called from + * \param line line it called from + * \param new pointer or NULL + */ +void * +mush_realloc_where(void *restrict ptr, size_t newsize, + const char *restrict check, const char *restrict filename, + int line) +{ + void *newptr; + + newptr = realloc(ptr, newsize); + + if (!ptr) + add_check(check); + else if (newsize == 0) + del_check(check, filename, line); + + return newptr; +} + +/** 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. + * \param filename file name it was called from + * \param line line it called from + */ +void +mush_free_where(void *restrict ptr, const char *restrict check, + const char *restrict filename, int line) +{ + del_check(check, filename, line); + free(ptr); + return; +} + +/** Turn on lots of noisy debug info in log/trace.log */ +/* #define SLAB_DEBUG */ + +/* Slab allocator functions */ +/** A struct that represents an unallocated object */ +struct slab_page_list { + struct slab_page_list *next; +}; + +/** A struct that represents one page's worth of objects */ +struct slab_page { + int nalloced; /**< Number of objects allocated from this page */ + int nfree; /**< Number of objects on this page's free list */ + void *last_obj; /**< Pointer to last object in page. */ + struct slab_page *next; /**< Pointer to next allocated page */ + struct slab_page_list *freelist; /**< Pointer to list of unallocated objects */ +}; + +/** Struct for a slab allocator */ +struct slab { + char name[64]; /**< Name of the slab */ + int item_size; /**< Size of the objects this slab returns */ + int items_per_page; /**< Number of objects that fit into a page */ + ptrdiff_t data_offset; /**< offset from start of the page where objects + are allocated from. */ + bool fill_strategy; /**< How to find empty nodes? true for + FIRST_FIT, false for BEST_FIT. */ + bool keep_last_empty; /**< False if empty pages are always deleted, + true to keep an empty page if it is the + only allocated page. */ + int hintless_threshold; /**< See documentation for + SLAB_HINTLESS_THRESHOLD option */ + struct slab_page *slabs; /**< Pointer to the head of the list of + allocated pages. */ +}; + + +/** Create a new slab allocator. + * \param name The name of the allocator + * \param item_size The size of objects to be allocated. It must be smaller + * than the size of a VM page (Usually 4 or 8 k) + * \return a pointer to the new slab allocator. + */ +slab * +slab_create(const char *name, size_t item_size) +{ + struct slab *sl; + size_t pgsize, offset; + + sl = malloc(sizeof(struct slab)); + pgsize = getpagesize(); + offset = sizeof(struct slab_page); + /* Start the objects 16-byte aligned */ + offset += sizeof(struct slab_page) % 16; + sl->data_offset = offset; + mush_strncpy(sl->name, name, 64); + sl->fill_strategy = 1; + sl->keep_last_empty = 0; + sl->hintless_threshold = 0; + sl->slabs = NULL; + if (item_size < SIZEOF_VOID_P) + item_size = SIZEOF_VOID_P; + /* Align objects after the first with the size of a pointer */ + item_size += item_size % SIZEOF_VOID_P; + sl->item_size = item_size; + sl->items_per_page = (pgsize - offset) / item_size; + + if (item_size >= (pgsize - offset)) { + do_rawlog(LT_TRACE, + "slab(%s): item_size of %lu bytes is too large for a pagesize of %lu bytes. Using malloc() for allocations from this slab.", + name, (unsigned long) item_size, (unsigned long) pgsize); + sl->items_per_page = 0; + return sl; + } + + return sl; +} + +/** Set a slab allocator option + * \param sl the allocator + * \param opt The option to set + * \param val Value to set option too (Not meaningful for all options) + */ +void +slab_set_opt(slab *sl, enum slab_options opt, int val + __attribute__ ((__unused__))) +{ + if (!sl) + return; + switch (opt) { + case SLAB_ALLOC_FIRST_FIT: + sl->fill_strategy = 1; + break; + case SLAB_ALLOC_BEST_FIT: + sl->fill_strategy = 0; + break; + case SLAB_ALWAYS_KEEP_A_PAGE: + sl->keep_last_empty = val; + break; + case SLAB_HINTLESS_THRESHOLD: + sl->hintless_threshold = val; + break; + default: + /* Unknown option */ + break; + } +} + +/** Allocate a new page. + * \param sl Allocator to create the page for. + * \return new page, NOT linked into the allocator's list of pages + */ +static struct slab_page * +slab_alloc_page(struct slab *sl) +{ + struct slab_page *sp; + uint8_t *page; + int n; + +#if defined(HAVE_VALLOC) && MALLOC_TYPE == 0 + /* valloc() allocates on a page boundry. Many malloc()s do also, + but prefer this in case of one that implements valloc() without + malloc() having the same behavior for chunks the size of a page. + + TODO: Consider using mmap() or /dev/null instead, and adding an + access-pattern option that uses madvise() to give usage hints to + the VM system. That might only do any good on multi-page allocations, + though. + */ + page = valloc(getpagesize()); +#else + page = malloc(getpagesize()); +#endif + + sp = (struct slab_page *) page; + sp->nfree = sl->items_per_page; + sp->nalloced = 0; + sp->freelist = NULL; + page = page + sl->data_offset; + for (n = 0; n < sl->items_per_page; n++) { + struct slab_page_list *item = (struct slab_page_list *) page; + page += sl->item_size; + item->next = sp->freelist; + sp->freelist = item; + } + sp->last_obj = sp->freelist; + sp->next = NULL; +#ifdef SLAB_DEBUG + do_rawlog(LT_TRACE, + "Allocating page starting at %p for slab(%s).\n\tFirst object allocated at %p, last object at %p", + (void *) sp, sl->name, (void *) (sp + sl->data_offset), + sp->last_obj); +#endif + + return sp; +} + +/** Allocate a new object from a page + * \param where the page to allocate from. + * \return pointer to object, or NULL if no room left on page + */ +static void * +slab_alloc_obj(struct slab_page *where) +{ + struct slab_page_list *obj; + + obj = where->freelist; + if (obj == NULL) + return NULL; + + where->freelist = obj->next; + where->nalloced += 1; + where->nfree -= 1; + + return obj; +} + +/** Return a new object allocated from a slab. + * \param sl the slab allocator + * \param hint If non-NULL, try to allocate new object on the same page. + * \return pointer to object, or NULL + */ +void * +slab_malloc(slab *sl, const void *hint) +{ + if (!sl) + return NULL; + + /* If objects are too big to fit in a single page, use plain malloc */ + if (sl->items_per_page == 0) + return malloc(sl->item_size); + + /* If no pages have been allocated, make one and use it. */ + if (!sl->slabs) { + sl->slabs = slab_alloc_page(sl); + return slab_alloc_obj(sl->slabs); + } + + if (!hint) { + /* Use first empty spot. */ + struct slab_page *page, *last = NULL, *best = NULL; + int best_free = INT_MAX; + for (page = sl->slabs; page; page = page->next) { + if (page->nfree > sl->hintless_threshold && sl->fill_strategy) + /* First fit */ + return slab_alloc_obj(page); + else if (page->nfree > sl->hintless_threshold) { + /* Best fit */ + if (page->nfree < best_free) { + best_free = page->nfree; + best = page; + if (best->nfree == sl->hintless_threshold + 1) + break; + } + } + last = page; + } + + if (best) + return slab_alloc_obj(best); + + /* All pages are full; allocate a new one */ + last->next = slab_alloc_page(sl); + return slab_alloc_obj(last->next); + } else { + struct slab_page *page, *last = NULL; + ptrdiff_t pgsize; + /* Okay. We have a hint for where to allocate the object. Find the + page the hint is on. */ + pgsize = getpagesize(); + for (page = sl->slabs; page; page = page->next) { + if (hint > (void *) page && hint <= page->last_obj) { + /* If there's space, use this page, otherwise, if using + first-fit, use the first page with room if using best-fit, + see if the next or previous page has room, otherwise, + normal best-fit match */ + if (page->nfree > 0) + return slab_alloc_obj(page); + if (sl->fill_strategy) + return slab_malloc(sl, NULL); + else if (page->next && page->next->nfree > 0) + return slab_alloc_obj(page->next); + else if (last && last->nfree > 0) + return slab_alloc_obj(last); + else + return slab_malloc(sl, NULL); + } + last = page; + } + /* This should never be reached, but handle it anyways. */ +#ifdef SLAB_DEBUG + do_rawlog(LT_TRACE, "page hint %p not found in slab(%s)", (void *) hint, + sl->name); +#endif + last->next = slab_alloc_page(sl); + return slab_alloc_obj(last->next); + } + return NULL; +} + +/** Free an allocated slab object + * \param sl the slab allocator + * \param obj the object to free + */ +void +slab_free(slab *sl, void *obj) +{ + struct slab_page *page, *last; + ptrdiff_t pgsize; + + /* If objects are too big to fit in a single page, use plain free */ + if (sl->items_per_page == 0) { + free(obj); + return; + } + + /* Find the page the object is on and push it into that page's free list */ + pgsize = getpagesize(); + last = NULL; + for (page = sl->slabs; page; page = page->next) { + if (obj > (void *) page && obj <= page->last_obj) { + struct slab_page_list *item = obj; +#ifdef SLAB_DEBUG + struct slab_page_list *scan; + for (scan = page->freelist; scan; scan = scan->next) + if (item == scan) + do_rawlog(LT_TRACE, + "Attempt to free already free object %p from page %p of slab(%s)", + (void *) item, (void *) page, sl->name); +#endif + item->next = page->freelist; + page->freelist = item; + page->nalloced -= 1; + page->nfree += 1; +#ifdef SLAB_DEBUG + assert(page->nalloced >= 0 && page->nalloced <= sl->items_per_page); + assert(page->nfree >= 0 && page->nfree <= sl->items_per_page); +#endif + if (page->nalloced == 0) { + /* Empty page. Free it. */ + + /* Unless it's the only allocated page and we want to keep it */ + if (sl->keep_last_empty && page == sl->slabs && !page->next) + return; + + if (last) + last->next = page->next; + else + sl->slabs = page->next; + +#ifdef SLAB_DEBUG + do_rawlog(LT_TRACE, "Freeing empty page %p of slab(%s)", (void *) page, + sl->name); +#endif + free(page); + } + return; + } + last = page; + } + /* Ooops. An object not allocated by this allocator! */ + do_rawlog(LT_TRACE, + "Attempt to free object %p not allocated by slab(%s)", + obj, sl->name); +} + +/** Destroy a slab and all objects allocated from it. + * Any objects allocated from the slab with pointers to + * objects allocated from outside the slab will NOT be freed. + * \param sl the slab to destroy. + */ +void +slab_destroy(slab *sl) +{ + struct slab_page *page, *next; + for (page = sl->slabs; page; page = next) { + next = page->next; + free(page); + } + free(sl); +} + +/** Describe a slab for @list allocations + * \param player who to display to + * \param sl the slab + */ +void +slab_describe(dbref player, slab *sl) +{ + struct slab_page *page; + int n = 0; + size_t allocated = 0, freed = 0; + int min_fill = INT_MAX, max_fill = 0; + int full = 0, under100 = 0, under75 = 0, under50 = 0, under25 = 0; + + if (!sl) + return; + + for (page = sl->slabs; page; page = page->next) { + double p; + n++; + allocated += page->nalloced; + freed += page->nfree; + if (page->nalloced > max_fill) + max_fill = page->nalloced; + if (page->nalloced < min_fill) + min_fill = page->nalloced; + p = (double) page->nalloced / (double) sl->items_per_page; + if (p == 1.0) + full += 1; + else if (p > 0.75) + under100 += 1; + else if (p > 0.50) + under75 += 1; + else if (p > 0.25) + under50 += 1; + else + under25 += 1; + } + + notify_format(player, "Allocator for %s:", sl->name); + notify_format(player, + " object size (bytes): %-6d objects per page: %-6d", + sl->item_size, sl->items_per_page); + notify_format(player, + " allocated pages: %-6d objects added via: %s", n, + sl->fill_strategy ? "first fit" : "best fit"); + notify_format(player, + " allocated objects: %-6ld free objects: %-6ld", + (unsigned long) allocated, (unsigned long) freed); + if (allocated > 0) { + notify_format(player, + " fewest allocs in page: %-6d most allocs in page: %-6d", + min_fill, max_fill); + notify_format(player, + " allocation average:%6.2f%% pages 100%% full: %-6d", + (((double) allocated / ((double) allocated + (double) freed)) + * 100.0), full); + notify_format(player, + " pages >75%% full: %-6d pages >50%% full: %-6d", + under100, under75); + notify_format(player, + " pages >25%% full: %-6d pages <25%% full: %d", + under50, under25); + } +} + + +extern slab *attrib_slab, *lock_slab, *boolexp_slab, *bvm_asmnode_slab, + *bvm_strnode_slab, *flag_slab, *player_dbref_slab, + *command_slab, *mail_slab, + *bque_slab, *text_block_slab, *function_slab, *memcheck_slab, *intmap_slab; +#ifdef CHAT_SYSTEM +extern slab *chanuser_slab, *chanlist_slab, *channel_slab; +#endif + +#if COMPRESSION_TYPE == 1 || COMPRESSION_TYPE == 2 +extern slab *huffman_slab; +#endif + +/** List information about slab allocators and memcheck data. Admin only. */ +void +do_list_allocations(dbref player) +{ + if (!Admin(player)) { + notify(player, T("Sorry.")); + return; + } + slab_describe(player, attrib_slab); + slab_describe(player, bque_slab); +#ifdef DEBUG + /* These should always be 0. No need to display them most of the + time. */ + slab_describe(player, boolexp_slab); + slab_describe(player, bvm_asmnode_slab); + slab_describe(player, bvm_strnode_slab); +#endif +#ifdef CHAT_SYSTEM + slab_describe(player, channel_slab); + slab_describe(player, chanlist_slab); + slab_describe(player, chanuser_slab); +#endif + slab_describe(player, command_slab); + slab_describe(player, flag_slab); + slab_describe(player, function_slab); +#if COMPRESSION_TYPE == 1 || COMPRESSION_TYPE == 2 + slab_describe(player, huffman_slab); +#endif + slab_describe(player, lock_slab); + slab_describe(player, mail_slab); + slab_describe(player, memcheck_slab); + slab_describe(player, text_block_slab); + slab_describe(player, player_dbref_slab); + slab_describe(player, intmap_slab); + + if (options.mem_check) { + notify(player, "malloc allocations:"); + list_mem_check(player); + } +} + +#ifdef WIN32 +/** Windows version of getpagesize() */ +unsigned int +getpagesize_win32(void) +{ + SYSTEM_INFO si; + GetSystemInfo(&si); + return si.dwPageSize; +} +#endif diff --git a/src/myrlimit.c b/src/myrlimit.c new file mode 100644 index 0000000..cf9c301 --- /dev/null +++ b/src/myrlimit.c @@ -0,0 +1,141 @@ +/** + * \file myrlimit.c + * + * \brief Resource limit utilities + * + * This file provides routines for modifying system resource limits + * with getrlimit/setrlimit, and similar stuff. + * + */ + +#include "copyrite.h" +#include "config.h" + +#include +#include +#ifdef I_SYS_TYPES +#include +#endif +#ifdef WIN32 +#define FD_SETSIZE 256 +#include +#include +#include +#define EWOULDBLOCK WSAEWOULDBLOCK +#endif +#ifdef I_UNISTD +#include +#endif +#ifdef I_SYS_TIME +#include +#endif +#ifdef HAVE_SYS_RESOURCE_H +#include +#endif +#include +#include + +#include "conf.h" +#include "version.h" +#include "externs.h" +#include "confmagic.h" + +#ifdef HAS_GETRLIMIT +void init_rlimit(void); +#endif +int how_many_fds(void); + +#ifdef WIN32 +static WSADATA wsadata; +#endif + +#ifdef HAS_GETRLIMIT +void +init_rlimit(void) +{ + /* Unlimit file descriptors. */ + /* Ultrix 4.4 and others may have getrlimit but may not be able to + * change number of file descriptors + */ +#ifdef RLIMIT_NOFILE + struct rlimit rlp; + + if (getrlimit(RLIMIT_NOFILE, &rlp)) { + penn_perror("init_rlimit: getrlimit()"); + return; + } + /* This check seems dumb, but apparently FreeBSD may return 0 for + * the max # of descriptors! + */ + if (rlp.rlim_max > rlp.rlim_cur) { + rlp.rlim_cur = rlp.rlim_max; + if (setrlimit(RLIMIT_NOFILE, &rlp)) + penn_perror("init_rlimit: setrlimit()"); + } +#endif + return; +} +#endif /* HAS_GETRLIMIT */ + +int +how_many_fds(void) +{ + /* Determine how many open file descriptors we're allowed + * In order, we'll try: + * 1. sysconf(_SC_OPEN_MAX) - POSIX.1 + * 2. OPEN_MAX constant - POSIX.1 limits.h + * 3. getdtablesize - BSD (which Config maps to ulimit or NOFILE if needed) + */ + static int open_max = 0; +#ifdef WIN32 + int iMaxSocketsAllowed; + unsigned short wVersionRequested = MAKEWORD(1, 1); + int err; +#endif + if (open_max) + return open_max; +#ifdef WIN32 + /* Typically, WIN32 allows many open sockets, but won't perform + * well if too many are used. The best approach is to give the + * admin a single point of control (MAX_LOGINS in MUSH.CNF) and then + * allow a few more connections than that here for clients to get access + * to an E-mail address or at least a title. 2 is an arbitrary number. + * + * If max_logins is set to 0 in mush.cnf (unlimited logins), + * we'll allocate 120 sockets for now. + * + * wsadata.iMaxSockets isn't valid for WinSock versions 2.0 + * and later, but we are requesting version 1.1, so it's valid. + */ + + /* Need to init Windows Sockets to get socket data */ + err = WSAStartup(wVersionRequested, &wsadata); + if (err) { + printf("Error %i on WSAStartup\n", err); + exit(1); + } + iMaxSocketsAllowed = options.max_logins ? (2 * options.max_logins) : 120; + if (wsadata.iMaxSockets < iMaxSocketsAllowed) + iMaxSocketsAllowed = wsadata.iMaxSockets; + return iMaxSocketsAllowed; +#else +#ifdef HAS_SYSCONF + errno = 0; + if ((open_max = sysconf(_SC_OPEN_MAX)) < 0) { + if (errno == 0) /* Value was indeterminate */ + open_max = 0; + } + if (open_max) + return open_max; +#endif +#ifdef OPEN_MAX + open_max = OPEN_MAX; + return open_max; +#endif + /* Caching getdtablesize is dangerous, since it's affected by + * getrlimit, so we don't. + */ + open_max = 0; + return getdtablesize(); +#endif /* WIN 32 */ +} diff --git a/src/mysocket.c b/src/mysocket.c index 455e653..720ad5e 100644 --- a/src/mysocket.c +++ b/src/mysocket.c @@ -14,6 +14,11 @@ #include #include +#ifdef WIN32 +#include +#include +#endif + #ifdef I_SYS_TYPES #include #endif @@ -65,11 +70,9 @@ #include #endif -#ifndef h_errno -#ifndef __CYGWIN__ +#if !defined(HAVE_H_ERRNO) && !defined(WIN32) extern int h_errno; #endif -#endif #include @@ -81,10 +84,21 @@ extern int h_errno; #include #endif -#include - #ifdef I_SYS_TIME #include +#ifdef TIME_WITH_SYS_TIME +#include +#endif +#else +#include +#endif + +#ifdef HAVE_POLL_H +#include +#endif + +#ifdef I_SYS_SELECT +#include #endif #include "conf.h" @@ -94,13 +108,8 @@ extern int h_errno; #include "ident.h" #include "confmagic.h" -#ifndef __ptr_t -#if defined (__cplusplus) || (defined (__STDC__) && __STDC__) -#define __ptr_t void * -#else -#define __ptr_t char * -#endif -#endif +static int connect_nonb + (int sockfd, const struct sockaddr *saptr, socklen_t salen, bool nonb); #ifndef INFOSLAVE @@ -149,18 +158,19 @@ ip_convert(struct sockaddr *host, int len) } #endif /* INFOSLAVE */ -/** Open a tcp connection to a given host and port. Basically +/** Open a connection to a given host and port. Basically * tcp_connect from UNPv1 * \param host hostname or ip address to connect to, as a string. + * \param socktype The type of socket - SOCK_STREAM or SOCK_DGRAM * \param myiterface pointer to sockaddr structure for specific interface. * \param myilen length of myiterface * \param port port to connect to. - * \param timeout pointer to timeout for connection. + * \param nonb true to do a nonblocking connect in the background. * \return file descriptor for connected socket, or -1 for failure. */ int -make_socket_conn(const char *host, struct sockaddr *myiterface, - socklen_t myilen, Port_t port, int *timeout) +make_socket_conn(const char *host, int socktype, struct sockaddr *myiterface, + socklen_t myilen, Port_t port, bool nonb) { struct addrinfo hints, *server, *save; char cport[NI_MAXSERV]; @@ -169,22 +179,25 @@ make_socket_conn(const char *host, struct sockaddr *myiterface, int err; memset(&hints, 0, sizeof(struct addrinfo)); - hints.ai_flags = AI_PASSIVE; hints.ai_family = AF_UNSPEC; /* Try to use IPv6 if available */ - hints.ai_socktype = SOCK_STREAM; + hints.ai_socktype = socktype; sprintf(cport, "%hu", port); if ((res = getaddrinfo(host, cport, &hints, &server)) != 0) { + lock_file(stderr); fprintf(stderr, "In getaddrinfo: %s\n", gai_strerror(res)); fprintf(stderr, "Host: %s Port %hu\n", host, port); fflush(stderr); + unlock_file(stderr); return -1; } if (!server) { + lock_file(stderr); fprintf(stderr, "Couldn't get address for host %s port %hu\n", host, port); fflush(stderr); + unlock_file(stderr); return -1; } @@ -195,18 +208,19 @@ make_socket_conn(const char *host, struct sockaddr *myiterface, if (s < 0) continue; - if (myiterface && myilen > 0) { - /* Bind to a specific interface. Needed for ident lookups */ + if (myiterface && myilen > 0 && myiterface->sa_family == server->ai_family) { + /* Bind to a specific interface. Don't even try for the case of + * an IPv4 socket and an IPv6 interface. Happens with ident, which + * seems to work okay without the bind(). */ if (bind(s, myiterface, myilen) < 0) - perror("bind failed (Possibly harmless)"); + penn_perror("bind failed (Possibly harmless)"); } - if ((err = connect_nonb(s, server->ai_addr, server->ai_addrlen, timeout)) == - 0) + if ((err = connect_nonb(s, server->ai_addr, server->ai_addrlen, nonb)) == 0) break; #ifdef DEBUG - perror("connect failed (Probably harmless)"); + penn_perror("connect failed (Probably harmless)"); #endif closesocket(s); @@ -223,8 +237,10 @@ make_socket_conn(const char *host, struct sockaddr *myiterface, if (port != IDPORT) { #endif + lock_file(stderr); fprintf(stderr, "Couldn't connect to %s on port %hu\n", host, port); fflush(stderr); + unlock_file(stderr); #ifndef DEBUG } #endif @@ -233,16 +249,18 @@ make_socket_conn(const char *host, struct sockaddr *myiterface, return s; } -/** Start listening to TCP on a given port. Basically tcp_listen + +/** Start listening on a given port. Basically tcp_listen * from UNPv1 * \param port port to listen on. + * \param socktype the type of socket - SOCK_STREAM or SOCK_DGRAM * \param addr pointer to sockaddr to copy address data to. * \param len length of addr. * \param host hostname or address to listen on, as a string. * \return file descriptor of listening socket, or -1 for failure. */ int -make_socket(Port_t port, union sockaddr_u *addr, socklen_t *len, +make_socket(Port_t port, int socktype, union sockaddr_u *addr, socklen_t * len, const char *host) { int s, opt, ipv = 4; @@ -252,7 +270,7 @@ make_socket(Port_t port, union sockaddr_u *addr, socklen_t *len, * Unix Network Programming, vol 1. If getaddrinfo() isn't * present on the system, we'll use our own version, also from UNPv1. */ struct addrinfo *server, *save, hints; - char cport[NI_MAXSERV]; + char portbuf[NI_MAXSERV], *cport; int res; memset(&hints, 0, sizeof(struct addrinfo)); @@ -263,9 +281,13 @@ make_socket(Port_t port, union sockaddr_u *addr, socklen_t *len, #else hints.ai_family = AF_UNSPEC; /* Try to use IPv6 if available */ #endif - hints.ai_socktype = SOCK_STREAM; + hints.ai_socktype = socktype; - sprintf(cport, "%hu", port); + if (port > 0) { + sprintf(portbuf, "%hu", port); + cport = portbuf; + } else + cport = NULL; if (strlen(host) == 0) host = NULL; @@ -290,14 +312,14 @@ make_socket(Port_t port, union sockaddr_u *addr, socklen_t *len, opt = 1; if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *) &opt, sizeof(opt)) < 0) { - perror("setsockopt (Possibly ignorable)"); + penn_perror("setsockopt (Possibly ignorable)"); continue; } if (bind(s, server->ai_addr, server->ai_addrlen) == 0) break; /* Success */ - perror("binding stream socket (Possibly ignorable)"); + penn_perror("binding stream socket (Possibly ignorable)"); closesocket(s); } while ((server = server->ai_next) != NULL); @@ -330,29 +352,69 @@ make_nonblocking(int s) #ifdef WIN32 unsigned long arg = 1; if (ioctlsocket(s, FIONBIO, &arg) == -1) { + penn_perror("make_nonblocking: ioctlsocket"); + mush_panic(T("Fatal network error!")); + } #else int flags; if ((flags = fcntl(s, F_GETFL, 0)) == -1) { - perror("make_nonblocking: fcntl"); + penn_perror("make_nonblocking: fcntl"); #ifndef INFOSLAVE - mush_panic("F_GETFL fcntl failed"); + mush_panic(T("Fatal network error!")); #else exit(1); #endif } - if (fcntl(s, F_SETFL, flags | O_NDELAY) == -1) { -#endif /* WIN32 */ - perror("make_nonblocking: fcntl"); + flags |= O_NDELAY; + + if (fcntl(s, F_SETFL, flags) == -1) { + penn_perror("make_nonblocking: fcntl"); #ifndef INFOSLAVE - mush_panic("O_NDELAY fcntl failed"); + mush_panic(T("Fatal network error!")); #else exit(1); #endif } +#endif } +/** Make a socket do blocking i/o. + * \param s file descriptor of socket. + */ +void +make_blocking(int s) +{ +#ifdef WIN32 + unsigned long arg = 0; + if (ioctlsocket(s, FIONBIO, &arg) == -1) { + penn_perror("make_blocking: ioctlsocket"); + mush_panic(T("Fatal network error")); + } +#else + int flags; + + if ((flags = fcntl(s, F_GETFL, 0)) == -1) { + penn_perror("make_blocking: fcntl"); +#ifndef INFOSLAVE + mush_panic(T("Fatal network error!")); +#else + exit(1); +#endif + } + + flags &= ~O_NDELAY; + if (fcntl(s, F_SETFL, flags) == -1) { + penn_perror("make_nonblocking: fcntl"); +#ifndef INFOSLAVE + mush_panic(T("Fatal network error!")); +#else + exit(1); +#endif + } +#endif +} #ifndef INFOSLAVE /** Enable TCP keepalive on the given socket if we can. @@ -374,7 +436,7 @@ set_keepalive(int s __attribute__ ((__unused__))) 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, @@ -399,24 +461,19 @@ set_keepalive(int s __attribute__ ((__unused__))) * \param sockfd file descriptor of socket. * \param saptr pointer to sockaddr structure with connection data. * \param salen length of saptr. - * \param timeout pointer to timeout value. If given, nonblocking connect. + * \param nonb true for a nonblocking connect in the background * \retval 0 success. * \retval -1 failure. */ int connect_nonb(int sockfd, const struct sockaddr *saptr, socklen_t salen, - int *timeout) + bool nonb) { - int n, error; - time_t start, end; - socklen_t len; - fd_set rset, wset; - struct timeval tval; + int n; - if (timeout && *timeout) + if (nonb) make_nonblocking(sockfd); - error = 0; if ((n = connect(sockfd, (const struct sockaddr *) saptr, salen)) < 0) #ifdef WIN32 if (n == SOCKET_ERROR && WSAGetLastError() != WSAEWOULDBLOCK) @@ -425,45 +482,52 @@ connect_nonb(int sockfd, const struct sockaddr *saptr, socklen_t salen, #endif return -1; - /* connect completed immediately or we did a blocking connect */ - if (!timeout || !*timeout || n == 0) - goto done; - - FD_ZERO(&rset); - FD_SET(sockfd, &rset); - wset = rset; - tval.tv_sec = *timeout; - tval.tv_usec = 0; - time(&start); + return 0; +} - if ((n = select(sockfd + 1, &rset, &wset, NULL, &tval)) == 0) { - closesocket(sockfd); /* timeout */ - errno = ETIMEDOUT; - return -1; +/** Wait up to N seconds for a non-blocking connect to establish. + * \param s the socket + * \param secs timeout value + * \return -1 on error, 0 if the socket is not yet connected, >0 on success + */ +int +wait_for_connect(int s, int secs) +{ + int res; +#ifdef HAVE_POLL + struct pollfd ev; + + ev.fd = s; + ev.events = POLLOUT; + if ((res = poll(&ev, 1, secs)) <= 0) { + if (res == 0) + errno = EINPROGRESS; + return res; + } else { + errno = ENOTCONN; + return ev.revents & POLLOUT; } - - time(&end); - *timeout -= end - start; - *timeout = *timeout < 0 ? 0 : *timeout; - - if (FD_ISSET(sockfd, &rset) || FD_ISSET(sockfd, &wset)) { - len = sizeof(error); - if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (__ptr_t) &error, &len) < 0) - return -1; /* Solaris pending error */ +#else + fd_set wrs; + struct timeval timeout, *to; + + FD_ZERO(&wrs); + FD_SET(s, &wrs); + timeout.tv_sec = secs; + timeout.tv_usec = 0; + if (secs >= 0) + to = &timeout; + if ((res = select(s + 1, NULL, &wrs, NULL, to)) <= 0) { +#ifndef WIN32 + if (res == 0) + errno = EINPROGRESS; +#endif + return res; } else - return -1; - -done: - - if (error) { - closesocket(sockfd); /* just in case */ - errno = error; - return -1; - } - return 0; + return FD_ISSET(s, &wrs); +#endif } - /* The following functions are from W. Ridhard Steven's libgai, * modified by Shawn Wagner for PennMUSH. These arn't full * implementations- they don't handle unix-domain sockets or named @@ -938,7 +1002,7 @@ getnameinfo(const struct sockaddr *sa, socklen_t salen, } #endif -#ifdef HAS_IPV6 +#ifdef HAVE_SOCKADDR_IN6 case AF_INET6:{ struct sockaddr_in6 *sain = (struct sockaddr_in6 *) sa; @@ -1029,7 +1093,7 @@ getaddrinfo(const char *hostname, const char *servname, } #endif -#ifdef HAS_IPV6 +#ifdef HAVE_SOCKADDR_IN6 /* 4check for an IPv6 hex string */ if ((isxdigit((unsigned char) sptr->host[0]) || sptr->host[0] == ':') && (strchr(sptr->host, ':') != NULL)) { @@ -1050,18 +1114,18 @@ getaddrinfo(const char *hostname, const char *servname, /* end ga3 */ /* include ga4 */ /* 4remainder of for() to look up hostname */ -#ifdef HAS_IPV6 +#ifdef HAVE_SOCKADDR_IN6 if ((_res.options & RES_INIT) == 0) res_init(); /* need this to set _res.options */ #endif if (nsearch == 2) { -#ifdef HAS_IPV6 +#ifdef HAVE_SOCKADDR_IN6 _res.options &= ~RES_USE_INET6; #endif hptr = gethostbyname2(sptr->host, sptr->family); } else { -#ifdef HAS_IPV6 +#ifdef HAVE_SOCKADDR_IN6 if (sptr->family == AF_INET6) _res.options |= RES_USE_INET6; else @@ -1164,7 +1228,7 @@ ga_echeck(const char *hostname, const char *servname, return (EAI_SOCKTYPE); /* invalid socket type */ break; #endif -#ifdef HAS_IPV6 +#ifdef HAVE_SOCKADDR_IN6 case AF_INET6: if (socktype != 0 && (socktype != SOCK_STREAM && @@ -1204,7 +1268,7 @@ ga_nsearch(const char *hostname, const struct addrinfo *hintsp, nsearch++; break; #endif -#ifdef HAS_IPV6 +#ifdef HAVE_SOCKADDR_IN6 case AF_INET6: search[nsearch].host = "0::0"; search[nsearch].family = AF_INET6; @@ -1212,7 +1276,7 @@ ga_nsearch(const char *hostname, const struct addrinfo *hintsp, break; #endif case AF_UNSPEC: -#ifdef HAS_IPV6 +#ifdef HAVE_SOCKADDR_IN6 search[nsearch].host = "0::0"; /* IPv6 first, then IPv4 */ search[nsearch].family = AF_INET6; nsearch++; @@ -1236,7 +1300,7 @@ ga_nsearch(const char *hostname, const struct addrinfo *hintsp, nsearch++; break; #endif -#ifdef HAS_IPV6 +#ifdef HAVE_SOCKADDR_IN6 case AF_INET6: search[nsearch].host = "0::1"; search[nsearch].family = AF_INET6; @@ -1244,7 +1308,7 @@ ga_nsearch(const char *hostname, const struct addrinfo *hintsp, break; #endif case AF_UNSPEC: -#ifdef HAS_IPV6 +#ifdef HAVE_SOCKADDR_IN6 search[nsearch].host = "0::1"; /* IPv6 first, then IPv4 */ search[nsearch].family = AF_INET6; nsearch++; @@ -1268,7 +1332,7 @@ ga_nsearch(const char *hostname, const struct addrinfo *hintsp, nsearch++; break; #endif -#ifdef HAS_IPV6 +#ifdef HAVE_SOCKADDR_IN6 case AF_INET6: search[nsearch].host = hostname; search[nsearch].family = AF_INET6; @@ -1276,7 +1340,7 @@ ga_nsearch(const char *hostname, const struct addrinfo *hintsp, break; #endif case AF_UNSPEC: -#ifdef HAS_IPV6 +#ifdef HAVE_SOCKADDR_IN6 search[nsearch].host = hostname; search[nsearch].family = AF_INET6; /* IPv6 first */ nsearch++; @@ -1342,7 +1406,7 @@ ga_aistruct(struct addrinfo ***paipnext, const struct addrinfo *hintsp, break; } #endif /* IPV4 */ -#ifdef HAS_IPV6 +#ifdef HAVE_SOCKADDR_IN6 case AF_INET6:{ struct sockaddr_in6 *sin6ptr; @@ -1461,7 +1525,7 @@ ga_port(struct addrinfo *aihead, int port, int socktype) nfound++; break; #endif -#ifdef HAS_IPV6 +#ifdef HAVE_SOCKADDR_IN6 case AF_INET6: ((struct sockaddr_in6 *) ai->ai_addr)->sin6_port = port; nfound++; diff --git a/src/myssl.c b/src/myssl.c index 391d553..02e0946 100644 --- a/src/myssl.c +++ b/src/myssl.c @@ -34,6 +34,11 @@ void shutdown_checkpoint(void); #endif #ifdef I_SYS_TIME #include +#ifdef TIME_WITH_SYS_TIME +#include +#endif +#else +#include #endif #include #include @@ -53,10 +58,6 @@ void shutdown_checkpoint(void); #include #endif #endif /* !WIN32 */ -#include -#ifdef I_SYS_WAIT -#include -#endif #include #include #include @@ -105,7 +106,7 @@ static DH *get_dh1024(void); static BIO *bio_err = NULL; static SSL_CTX *ctx = NULL; -unsigned int genrand_int32(void); +uint32_t genrand_int32(void); /** Initialize the SSL context. * \return pointer to SSL context object. @@ -131,7 +132,7 @@ ssl_init(void) /* 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. */ - unsigned int gibberish[4]; + uint32_t gibberish[4]; int n; for (n = 0; n < 4; n++) @@ -141,8 +142,10 @@ ssl_init(void) reps += 1; } + do_rawlog(LT_ERR, "Seeded after %u %s.", reps, reps > 1 ? "cycles" : "cycle"); + /* Set up SIGPIPE handler here? */ /* Create context */ @@ -186,7 +189,7 @@ ssl_init(void) /* Set up DH callback */ dh = get_dh1024(); - SSL_CTX_set_tmp_dh(ctx, get_dh1024()); + SSL_CTX_set_tmp_dh(ctx, dh); /* The above function makes a private copy of this */ DH_free(dh); @@ -253,16 +256,32 @@ get_dh1024(void) }; 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. diff --git a/src/notify.c b/src/notify.c index fa1b81c..6c43e15 100644 --- a/src/notify.c +++ b/src/notify.c @@ -26,6 +26,11 @@ #endif #ifdef I_SYS_TIME #include +#ifdef TIME_WITH_SYS_TIME +#include +#endif +#else +#include #endif #include #ifdef I_SYS_SOCKET @@ -44,7 +49,6 @@ #include #endif #endif /* !WIN32 */ -#include #include #include #include @@ -75,8 +79,6 @@ #include "ident.h" #include "strtree.h" #include "log.h" - - #include "mymalloc.h" #ifdef CHAT_SYSTEM @@ -88,7 +90,6 @@ extern CHAN *channels; #include "game.h" #include "confmagic.h" - static int under_limit = 1; /** Default connection, nothing special */ @@ -170,6 +171,8 @@ enum na_type { /** Number of possible message text renderings */ #define MESSAGE_TYPES 12 +/* These should be removed. I can't imagine anyone uses them in hacks, + * but I'm leaving them here just in case... */ #define TA_BGC 0 /**< Text attribute background color */ #define TA_FGC 1 /**< Text attribute foreground color */ #define TA_BOLD 2 /**< Text attribute bold/hilite */ @@ -186,119 +189,16 @@ struct notify_strings { int made; /**< True if message has been rendered. */ }; -static void fillstate(int state[], const unsigned char **f); -static void ansi_change_state(char *t, char **o, int color, int *state, - int *newstate); static enum na_type notify_type(DESC *d); static void free_strings(struct notify_strings messages[]); static void zero_strings(struct notify_strings messages[]); +static int output_ansichange(ansi_data *states, int *ansi_ptr, + const unsigned char **ptr, char *buff, char **bp); static unsigned char *notify_makestring(const char *message, struct notify_strings messages[], enum na_type type); -static void -fillstate(int state[6], const unsigned char **f) -{ - const unsigned char *p; - int i; - int n; - p = *f; - p++; - if (*p != '[') { - while (*p && *p != 'm') - p++; - } else { - p++; - while (*p && *p != 'm') { - if ((*p > '9') || (*p < '0')) { - /* Nada */ - } else if (!(*(p + 1)) || (*(p + 1) == 'm') || (*(p + 1) == ';')) { - /* ShortCode */ ; - switch (*p) { - case '0': - for (i = 0; i < 6; i++) - state[i] = 0; - break; - case '1': - state[TA_BOLD] = 1; - break; - case '7': - state[TA_REV] = 1; - break; - case '5': - state[TA_BLINK] = 1; - break; - case '4': - state[TA_ULINE] = 1; - break; - } - } else { - n = (*p - '0') * 10; - p++; - n += (*p - '0'); - if ((n >= 30) && (n <= 37)) - state[TA_FGC] = n - 29; - else if ((n >= 40) && (n <= 47)) - state[TA_BGC] = n - 39; - } - p++; - } - } - if ((p != *f) && (*p != 'm')) - p--; - *f = p; -} - -/** Add an ansi tag if it's needed here */ -#define add_ansi_if(x,c) \ - do { \ - if (newstate[(x)] && (newstate[(x)]!=state[(x)])) { \ - if (i) safe_chr(';',t,o); \ - safe_str((c),t,o); \ - i=1; \ - } \ - } while (0) - -static void -ansi_change_state(char *t, char **o, int color, int *state, int *newstate) -{ - int i, n; - if ((state[TA_BOLD] && !newstate[TA_BOLD]) || - (state[TA_REV] && !newstate[TA_REV]) || - (state[TA_BLINK] && !newstate[TA_BLINK]) || - (state[TA_ULINE] && !newstate[TA_ULINE]) || - (color && state[TA_FGC] && !newstate[TA_FGC]) || - (color && state[TA_BGC] && !newstate[TA_BGC])) { - for (n = 0; n < 6; n++) - state[n] = 0; - safe_str(ANSI_NORMAL, t, o); - } - if ((newstate[TA_BOLD] && (newstate[TA_BOLD] != state[TA_BOLD])) || - (newstate[TA_REV] && (newstate[TA_REV] != state[TA_REV])) || - (newstate[TA_BLINK] && (newstate[TA_BLINK] != state[TA_BLINK])) || - (newstate[TA_ULINE] && (newstate[TA_ULINE] != state[TA_ULINE])) || - (color && newstate[TA_FGC] && (newstate[TA_FGC] != state[TA_FGC])) || - (color && newstate[TA_BGC] && (newstate[TA_BGC] != state[TA_BGC]))) { - safe_chr(ESC_CHAR, t, o); - safe_chr('[', t, o); - i = 0; - add_ansi_if(TA_BOLD, "1"); - add_ansi_if(TA_REV, "7"); - add_ansi_if(TA_BLINK, "5"); - add_ansi_if(TA_ULINE, "4"); - if (color) { - add_ansi_if(TA_FGC, unparse_integer(newstate[TA_FGC] + 29)); - add_ansi_if(TA_BGC, unparse_integer(newstate[TA_BGC] + 39)); - } - safe_chr('m', t, o); - } - for (n = 0; n < 6; n++) - state[n] = newstate[n]; -} - -#undef add_ansi_if - static void zero_strings(struct notify_strings messages[]) { @@ -319,6 +219,58 @@ free_strings(struct notify_strings messages[]) mush_free(messages[n].message, "string"); } +static int +output_ansichange(ansi_data *states, int *ansi_ptr, + const unsigned char **ptr, char *buff, char **bp) +{ + const unsigned char *p = *ptr; + int newaptr = *ansi_ptr; + int retval = 0; + ansi_data cur = states[*ansi_ptr]; + + /* This is color */ + while (*p && + ((*p == TAG_START && *(p + 1) == MARKUP_COLOR) || (*p == ESC_CHAR))) { + switch (*p) { + case TAG_START: + p += 2; + if (*p != '/') { + newaptr++; + define_ansi_data(&(states[newaptr]), (const char *) p); + } else { + if (*(p + 1) == 'a') { + newaptr = 0; + } else { + if (newaptr > 0) + newaptr--; + } + } + while (*p && *p != TAG_END) + p++; + break; + case ESC_CHAR: + newaptr++; + read_raw_ansi_data(&states[newaptr], (const char *) p); + while (*p && *p != 'm') + p++; + break; + } + if (newaptr > 0) + nest_ansi_data(&(states[newaptr - 1]), &(states[newaptr])); + /* Advance past the tag ending, if there's more. */ + if (*p && ((*(p + 1) == TAG_START && *(p + 2) == MARKUP_COLOR) || + (*(p + 1) == ESC_CHAR))) + p++; + } + /* Do we print anything? */ + if (*p && *ptr != p) { + retval = write_raw_ansi_data(&cur, &(states[newaptr]), buff, bp); + *(ansi_ptr) = newaptr; + } + *ptr = p; + return retval; +} + static unsigned char * notify_makestring(const char *message, struct notify_strings messages[], enum na_type type) @@ -326,9 +278,6 @@ notify_makestring(const char *message, struct notify_strings messages[], char *o; const unsigned char *p; char *t; - int state[6] = { 0, 0, 0, 0, 0, 0 }; - int newstate[6] = { 0, 0, 0, 0, 0, 0 }; - int changed = 0; int color = 0; int strip = 0; int pueblo = 0; @@ -338,6 +287,17 @@ notify_makestring(const char *message, struct notify_strings messages[], return messages[type].message; messages[type].made = 1; + static ansi_data states[BUFFER_LEN]; + int ansi_ptr, ansifix; + ansi_ptr = 0; + ansifix = 0; + + /* Everything is explicitly off by default */ + states[0].bits = 0; + states[0].offbits = 0; + states[0].fore = 0; + states[0].back = 0; + p = (unsigned char *) message; o = tbuf; t = o; @@ -427,28 +387,26 @@ notify_makestring(const char *message, struct notify_strings messages[], while (*p) { switch ((unsigned char) *p) { case IAC: - if (changed) { - changed = 0; - ansi_change_state(t, &o, color, state, newstate); - } if (type == NA_TANSI || type == NA_TCOLOR) - safe_str("\xFF\xFF", t, &o); + safe_strl("\xFF\xFF", 2, t, &o); else if (strip && accent_table[IAC].base) safe_str(accent_table[IAC].base, t, &o); else safe_chr((char) IAC, t, &o); break; case TAG_START: - if (pueblo) { + if (*(p + 1) == MARKUP_COLOR) { + ansifix += output_ansichange(states, &ansi_ptr, &p, t, &o); + } else if (pueblo && (*(p + 1) == MARKUP_HTML)) { safe_chr('<', t, &o); - p++; + /* Skip over the 'p' for Pueblo */ + p += 2; while ((*p) && (*p != TAG_END)) { safe_chr(*p, t, &o); p++; } safe_chr('>', t, &o); } else { - /* Non-pueblo */ while (*p && *p != TAG_END) p++; } @@ -459,14 +417,10 @@ notify_makestring(const char *message, struct notify_strings messages[], case '\r': break; case ESC_CHAR: - fillstate(newstate, &p); - changed = 1; + /* After the ansi changes, I really hope we don't encounter this. */ + ansifix += output_ansichange(states, &ansi_ptr, &p, t, &o); break; default: - if (changed) { - changed = 0; - ansi_change_state(t, &o, color, state, newstate); - } if (pueblo) { if (strip) { /* Even if we're NOACCENTS, we must still translate a few things */ @@ -499,12 +453,30 @@ notify_makestring(const char *message, struct notify_strings messages[], safe_chr(*p, t, &o); } } - p++; + if (*p) + p++; + } + /* We possibly have some unclosed ansi. Force an + * ANSI_NORMAL for now. */ + if (ansifix || (ansi_ptr && safe_str(ANSI_RAW_NORMAL, t, &o))) { + int sub = 7; + char *ptr; + int q; + ptr = t + BUFFER_LEN - sub; + for (q = 20; q > 0 && *ptr != ESC_CHAR; q--, ptr--) ; + if (pueblo) { + for (q = 20; q > 0 && *ptr != ESC_CHAR && *ptr != '<'; q--, ptr--) ; + } else { + for (q = 20; q > 0 && *ptr != ESC_CHAR; q--, ptr--) ; + } + if (q > 0) { + o = ptr; + } else { + o = t + BUFFER_LEN - sub; + } + safe_str(ANSI_RAW_NORMAL, t, &o); + *o = '\0'; } - if (state[TA_BOLD] || state[TA_REV] || - state[TA_BLINK] || state[TA_ULINE] || - (color && (state[TA_FGC] || state[TA_BGC]))) - safe_str(ANSI_NORMAL, t, &o); break; } @@ -919,7 +891,8 @@ notify_anything_loc(dbref speaker, na_lookup func, a = atr_get_noparent(target, "LISTEN"); if (a) { char match_space[BUFFER_LEN * 2]; - int match_space_len = BUFFER_LEN * 2; + ssize_t match_space_len = BUFFER_LEN * 2; + if (!tbuf1) tbuf1 = (char *) mush_malloc(BUFFER_LEN, "string"); strcpy(tbuf1, atr_value(a)); @@ -1165,101 +1138,7 @@ notify_list(dbref speaker, dbref thing, const char *atr, const char *msg, } } } - free((Malloc_t) orig); -} - -/** Safely add a tag into a buffer. - * If we support pueblo, this function adds the tag start token, - * the tag, and the tag end token. If not, it does nothing. - * If we can't fit the tag in, we don't put any of it in. - * \param a_tag the html tag to add. - * \param buf the buffer to append to. - * \param bp pointer to address in buf to insert. - * \retval 0, successfully added. - * \retval 1, tag wouldn't fit in buffer. - */ -int -safe_tag(char const *a_tag, char *buf, char **bp) -{ - int result = 0; - char *save = buf; - - if (SUPPORT_PUEBLO) { - result = safe_chr(TAG_START, buf, bp); - result = safe_str(a_tag, buf, bp); - result = safe_chr(TAG_END, buf, bp); - } - /* If it didn't all fit, rewind. */ - if (result) - *bp = save; - - return result; -} - -/** Safely add a closing tag into a buffer. - * If we support pueblo, this function adds the tag start token, - * a slash, the tag, and the tag end token. If not, it does nothing. - * If we can't fit the tag in, we don't put any of it in. - * \param a_tag the html tag to add. - * \param buf the buffer to append to. - * \param bp pointer to address in buf to insert. - * \retval 0, successfully added. - * \retval 1, tag wouldn't fit in buffer. - */ -int -safe_tag_cancel(char const *a_tag, char *buf, char **bp) -{ - int result = 0; - char *save = buf; - - if (SUPPORT_PUEBLO) { - result = safe_chr(TAG_START, buf, bp); - result = safe_chr('/', buf, bp); - result = safe_str(a_tag, buf, bp); - result = safe_chr(TAG_END, buf, bp); - } - /* If it didn't all fit, rewind. */ - if (result) - *bp = save; - - return result; -} - -/** Safely add a tag, some text, and a matching closing tag into a buffer. - * If we can't fit the stuff, we don't put any of it in. - * \param a_tag the html tag to add. - * \param params tag parameters. - * \param data the text to wrap the tag around. - * \param buf the buffer to append to. - * \param bp pointer to address in buf to insert. - * \param player the player involved in all this, or NOTHING if internal. - * \retval 0, successfully added. - * \retval 1, tagged text wouldn't fit in buffer. - */ -int -safe_tag_wrap(char const *a_tag, char const *params, char const *data, - char *buf, char **bp, dbref player) -{ - int result = 0; - char *save = buf; - - if (SUPPORT_PUEBLO) { - result = safe_chr(TAG_START, buf, bp); - result = safe_str(a_tag, buf, bp); - if (params && *params && ok_tag_attribute(player, (char *) params)) { - result = safe_chr(' ', buf, bp); - result = safe_str(params, buf, bp); - } - result = safe_chr(TAG_END, buf, bp); - } - result = safe_str(data, buf, bp); - if (SUPPORT_PUEBLO) { - result = safe_tag_cancel(a_tag, buf, bp); - } - /* If it didn't all fit, rewind. */ - if (result) - *bp = save; - return result; + free((Malloc_t) orig); /* TODO: this should be using a memory tracker */ } /** Wrapper to notify a single player with a message, unconditionally. @@ -1311,18 +1190,22 @@ flag_broadcast(const char *flag1, const char *flag2, const char *fmt, ...) } } - +slab *text_block_slab = NULL; /**< Slab for 'struct text_block' allocations */ static struct text_block * make_text_block(const unsigned char *s, int n) { struct text_block *p; - p = - (struct text_block *) mush_malloc(sizeof(struct text_block), "text_block"); + if (text_block_slab == NULL) { + text_block_slab = slab_create("output lines", sizeof(struct text_block)); + /* See what stats are like on M*U*S*H, maybe change */ + slab_set_opt(text_block_slab, SLAB_ALLOC_FIRST_FIT, 1); + slab_set_opt(text_block_slab, SLAB_ALWAYS_KEEP_A_PAGE, 1); + } + p = slab_malloc(text_block_slab, NULL); if (!p) mush_panic("Out of memory"); - p->buf = - (unsigned char *) mush_malloc(sizeof(unsigned char) * n, "text_block_buff"); + p->buf = mush_malloc(n, "text_block_buff"); if (!p->buf) mush_panic("Out of memory"); @@ -1342,7 +1225,7 @@ free_text_block(struct text_block *t) if (t) { if (t->buf) mush_free((Malloc_t) t->buf, "text_block_buff"); - mush_free((Malloc_t) t, "text_block"); + slab_free(text_block_slab, t); } } diff --git a/src/parse.c b/src/parse.c index 3d8b8ee..3f8cded 100644 --- a/src/parse.c +++ b/src/parse.c @@ -16,6 +16,10 @@ #include #include #include +#ifdef HAVE_INTTYPES_H +#include +#endif +#include #include "conf.h" #include "externs.h" @@ -28,7 +32,7 @@ #include "mushdb.h" #include "parse.h" #include "attrib.h" -#include "pcre.h" +#include "mypcre.h" #include "flags.h" #include "log.h" #include "mymalloc.h" @@ -41,7 +45,7 @@ int global_fun_invocations; int global_fun_recursions; /* extern int re_subpatterns; */ /* extern int *re_offsets; */ -/* extern char *re_from; */ +/* extern ansi_string *re_from; */ extern sig_atomic_t cpu_time_limit_hit; extern int cpu_limit_warning_sent; extern int iter_break; @@ -147,13 +151,12 @@ qparse_dbref(const char *s) dbref parse_objid(char const *str) { - char *p; + const char *p; if ((p = strchr(str, ':'))) { char tbuf1[BUFFER_LEN]; dbref it; /* A unique id, probably */ - strncpy(tbuf1, str, (p - str)); - tbuf1[p - str] = '\0'; + mush_strncpy(tbuf1, str, (p - str) + 1); it = parse_dbref(tbuf1); if (GoodObject(it)) { time_t matchtime; @@ -179,7 +182,7 @@ parse_objid(char const *str) * \retval 1 str represents a true value. * \retval 0 str represents a false value. */ -int +bool parse_boolean(char const *str) { if (TINY_BOOLEANS) { @@ -215,7 +218,7 @@ parse_boolean(char const *str) * \retval 1 string is a valid boolean. * \retval 0 string is not a valid boolean. */ -int +bool is_boolean(char const *str) { if (TINY_BOOLEANS) @@ -231,7 +234,7 @@ is_boolean(char const *str) * \retval 1 string is a dbref. * \retval 0 string is not a dbref. */ -int +bool is_dbref(char const *str) { if (!str || (*str != NUMBER_TOKEN) || !*(str + 1)) @@ -253,29 +256,33 @@ is_dbref(char const *str) * \retval 1 string is an objid * \retval 0 string is not an objid. */ -int +bool is_objid(char const *str) { static pcre *re = NULL; const char *errptr; int erroffset; + char *val; + size_t vlen; if(!str) return 0; if (!re) re = pcre_compile("^#-?\\d+(?::\\d+)?$", 0, &errptr, &erroffset, NULL); - return (pcre_exec(re, NULL, str, strlen(str), 0, 0, NULL, 0) >= 0); + val = remove_markup((const char *) str, &vlen); + return pcre_exec(re, NULL, val, vlen - 1, 0, 0, NULL, 0) >= 0; } + /** Is string an integer? * To TinyMUSH, any string is an integer. To PennMUSH, a string that - * passes strtol is an integer, and a blank string is an integer + * passes parse_int is an integer, and a blank string is an integer * if NULL_EQ_ZERO is turned on. * \param str string to check. * \retval 1 string is an integer. * \retval 0 string is not an integer. */ -int +bool is_integer(char const *str) { char *end; @@ -290,21 +297,21 @@ is_integer(char const *str) if (*str == '\0') return NULL_EQ_ZERO; errno = 0; - strtol(str, &end, 10); + parse_int(str, &end, 10); if (errno == ERANGE || *end != '\0') return 0; return 1; } -/** Is string an uinteger? +/** Is string an unsigned integer? * To TinyMUSH, any string is an uinteger. To PennMUSH, a string that - * passes strtoul is an uinteger, and a blank string is an uinteger + * passes parse_uint is an uinteger, and a blank string is an uinteger * if NULL_EQ_ZERO is turned on. * \param str string to check. * \retval 1 string is an uinteger. * \retval 0 string is not an uinteger. */ -int +bool is_uinteger(char const *str) { char *end; @@ -322,7 +329,7 @@ is_uinteger(char const *str) if (!(isdigit((unsigned char) *str) || *str == '+')) return 0; errno = 0; - strtoul(str, &end, 10); + parse_uint(str, &end, 10); if (errno == ERANGE || *end != '\0') return 0; return 1; @@ -334,7 +341,7 @@ is_uinteger(char const *str) * \retval 1 string is a strict number. * \retval 0 string is not a strict number. */ -int +bool is_strict_number(char const *str) { char *end; @@ -348,12 +355,14 @@ is_strict_number(char const *str) return end > str; } +#ifndef HAVE_ISNORMAL /** Is string a number that isn't inf or nan? + * Only needed for systems without isnormal() * \param num NVAL * \retval 1 num is a good number. * \retval 0 num is not a good number. */ -int +bool is_good_number(NVAL val) { char numbuff[128]; @@ -368,14 +377,15 @@ is_good_number(NVAL val) return 0; return 1; } +#endif /** Is string an integer by the strict definition? - * A strict integer is a non-null string that passes strtol. + * A strict integer is a non-null string that passes parse_int. * \param str string to check. * \retval 1 string is a strict integer. * \retval 0 string is not a strict integer. */ -int +bool is_strict_integer(char const *str) { char *end; @@ -383,7 +393,7 @@ is_strict_integer(char const *str) if (!str) return 0; errno = 0; - val = strtol(str, &end, 10); + val = parse_int(str, &end, 10); if (errno == ERANGE || *end != '\0') return 0; return end > str; @@ -396,7 +406,7 @@ is_strict_integer(char const *str) * \retval 1 string is a number. * \retval 0 string is not a number. */ -int +bool is_number(char const *str) { /* If we're emulating Tiny, anything is a number */ @@ -409,6 +419,137 @@ is_number(char const *str) return is_strict_number(str); } +/** Convert a string containing a signed integer into an int. + * Does not do any format checking. Invalid strings will return 0. + * Use this instead of strtol() when storing to an int to avoid problems + * where sizeof(int) < sizeof(long). + * \param s The string to convert + * \param end pointer to store the end of the parsed part of the string in + * if not NULL. + * \param base the base to convert from. + * \return the number, or INT_MIN on underflow, INT_MAX on overflow, + * with errno set to ERANGE. + */ +int +parse_int(const char *s, char **end, int base) +{ + long x; + + x = strtol(s, end, base); + +#if SIZEOF_INT == SIZEOF_LONG + return x; +#else + /* These checks are only meaningful on 64-bit systems */ + if (x < INT_MIN) { + errno = ERANGE; + return INT_MIN; + } else if (x > INT_MAX) { + errno = ERANGE; + return INT_MAX; + } else + return x; +#endif +} + +/** Convert a string containing a signed integer into an int32_t. + * Does not do any format checking. Invalid strings will return 0. + * \param s The string to convert + * \param end pointer to store the end of the parsed part of the string in + * if not NULL. + * \param base the base to convert from. + * \return the number, or INT32_MIN on underflow, INT32_MAX on overflow, + * with errno set to ERANGE. + */ +int32_t +parse_int32(const char *s, char **end, int base) +{ +#if SIZEOF_INT == 4 + return parse_int(s, end, base); +#elif defined(SCNd32) + /* This won't do overflow checking, which is why it isn't first */ + const char *fmt; + int32_t val; + + if (base == 10) + fmt = "%" SCNd32; + else if (base == 8) + fmt = "%" SCNo32; + else if (base == 16) + fmt = "%" SCNx32; + else + /* Unsupported base in this mode */ + return 0; + + if (sscanf(s, fmt, &val) != 1) + return 0; + else + return val; +#else +#error "No way to parse a 32-bit integer string" +#endif +} + + +/** Convert a string containing an unsigned integer into an int. + * Does not do any format checking. Invalid strings will return 0. + * Use this instead of strtoul() when storing to an int to avoid problems + * where sizeof(int) < sizeof(long). + * \param s The string to convert + * \return the number, or UINT_MAX on overflow + * with errno set to ERANGE. + */ +unsigned int +parse_uint(const char *s, char **end, int base) +{ + unsigned long x; + + x = strtoul(s, end, base); + +#if SIZEOF_INT == SIZEOF_LONG + return x; +#else + /* These checks are only meaningful on 64-bit systems */ + if (x > UINT_MAX) { + errno = ERANGE; + return UINT_MAX; + } else + return x; +#endif +} + +/** Convert a string containing an unsigned integer into an uint32_t. + * Does not do any format checking. Invalid strings will return 0. + * \param s The string to convert + * \param end pointer to store the end of the parsed part of the string in + * if not NULL. + * \param base the base to convert from. + * \return the number, or UINT32_MIN on underflow, UINT32_MAX on overflow, + * with errno set to ERANGE. + */ +uint32_t +parse_uint32(const char *s, char **end, int base) +{ +#if SIZEOF_INT == 4 + return parse_uint(s, end, base); +#elif defined(SCNu32) + /* This won't do overflow checking, which is why it isn't first */ + const char *fmt; + uint32_t val; + + if (base != 10) + return 0; + + if (sscanf(s, SCNu32, &val) != 1) + return 0; + else + return val; +#else +#error "No way to parse a 32-bit integer string" +#endif +} + + /* Table of interesting characters for process_expression() */ extern char active_table[UCHAR_MAX + 1]; /* Indexes of valid q-regs into the global_eval_context.renv array. -1 is error. */ @@ -472,8 +613,10 @@ extern signed char qreg_indexes[UCHAR_MAX + 1]; int process_expression(char *buff, char **bp, char const **str, dbref executor, dbref caller, dbref enactor, - int eflags, int tflags, PE_Info * pe_info) + int eflags, int tflags, PE_Info *pe_info) { + char savec, nextc; + char *savepos; int debugging = 0, made_info = 0; char *debugstr = NULL, *sourcestr = NULL; char *realbuff = NULL, *realbp = NULL; @@ -485,9 +628,8 @@ process_expression(char *buff, char **bp, char const **str, int temp_eflags; int old_iter_limit; int qindex; - int e_len; int retval = 0; - const char *e_msg; + ATTR *attrib; if (!buff || !bp || !str || !*str) return 0; @@ -551,10 +693,12 @@ process_expression(char *buff, char **bp, char const **str, } if (CALL_LIMIT && (pe_info->call_depth++ > CALL_LIMIT)) { + const char *e_msg; + size_t e_len; e_msg = T(e_call); e_len = strlen(e_msg); if ((buff + e_len > *bp) || strcmp(e_msg, *bp - e_len)) - safe_str(e_msg, buff, bp); + safe_strl(e_msg, e_len, buff, bp); goto exit_sequence; } @@ -602,11 +746,6 @@ process_expression(char *buff, char **bp, char const **str, eflags &= ~PE_COMMAND_BRACES; for (;;) { - if(iter_break > 0) { - while(*str && **str) - (*str)++; - goto exit_sequence; - } /* Find the first "interesting" character */ { char const *pos; @@ -661,9 +800,17 @@ process_expression(char *buff, char **bp, char const **str, goto exit_sequence; } - switch (**str) { - case 0x1B: /* ANSI escapes. */ + case TAG_START: + /* Skip over until TAG_END. */ + for (; *str && **str && **str != TAG_END; (*str)++) + safe_chr(**str, buff, bp); + if (*str && **str) { + safe_chr(**str, buff, bp); + (*str)++; + } + break; + case ESC_CHAR: /* ANSI escapes. */ /* Skip over until the 'm' that matches the end. */ for (; *str && **str && **str != 'm'; (*str)++) safe_chr(**str, buff, bp); @@ -672,58 +819,56 @@ process_expression(char *buff, char **bp, char const **str, (*str)++; } break; - case '$': /* Dollar subs for regedit() */ + case '$': /* Dollar subs for regedit() */ if ((eflags & (PE_DOLLAR | PE_EVALUATE)) == (PE_DOLLAR | PE_EVALUATE) && - global_eval_context.re_subpatterns >= 0 && - global_eval_context.re_offsets != NULL && - global_eval_context.re_from != NULL) { - char obuf[BUFFER_LEN]; - int p = -1; + global_eval_context.re_subpatterns >= 0 && + global_eval_context.re_offsets != NULL && + global_eval_context.re_from != NULL) { + int p = -1; char subspace[BUFFER_LEN]; char *named_substring = NULL; - obuf[0] = '\0'; - (*str)++; - /* Check the first two characters after the $ for a number */ - if (isdigit((unsigned char) **str)) { - p = **str - '0'; - (*str)++; - } else if (**str == '<') { - char *nbuf = subspace; - (*str)++; - for (; *str && **str && **str != '>'; (*str)++) - safe_chr(**str, subspace, &nbuf); - *nbuf = '\0'; - if (*str && **str) - (*str)++; - if (is_strict_integer(subspace)) - p = abs(parse_integer(subspace)); - else - named_substring = subspace; - } else { - safe_chr('$', buff, bp); - break; - } - - if (named_substring) { - pcre_copy_named_substring(global_eval_context.re_code, - global_eval_context.re_from, - global_eval_context.re_offsets, - global_eval_context.re_subpatterns, - named_substring, obuf, BUFFER_LEN); - } else { - pcre_copy_substring(global_eval_context.re_from, - global_eval_context.re_offsets, - global_eval_context.re_subpatterns, - p, obuf, BUFFER_LEN); - } - safe_str(obuf, buff, bp); + (*str)++; + /* Check the first character after the $ for a number */ + if (isdigit((unsigned char) **str)) { + p = **str - '0'; + (*str)++; + } else if (**str == '<') { + /* Look for a named or numbered subexpression */ + char *nbuf = subspace; + (*str)++; + for (; *str && **str && **str != '>'; (*str)++) + safe_chr(**str, subspace, &nbuf); + *nbuf = '\0'; + if (*str && **str) + (*str)++; + if (is_strict_integer(subspace)) + p = abs(parse_integer(subspace)); + else + named_substring = subspace; + } else { + safe_chr('$', buff, bp); + break; + } + + if (named_substring != NULL) { + ansi_pcre_copy_named_substring(global_eval_context.re_code, + global_eval_context.re_from, + global_eval_context.re_offsets, + global_eval_context.re_subpatterns, + named_substring, 0, buff, bp); + } else { + ansi_pcre_copy_substring(global_eval_context.re_from, + global_eval_context.re_offsets, + global_eval_context.re_subpatterns, + p, 0, buff, bp); + } } else { safe_chr('$', buff, bp); (*str)++; } break; - case '%': /* Percent substitutions */ + case '%': /* Percent substitutions */ if (!(eflags & PE_EVALUATE) || (*bp - buff >= BUFFER_LEN - 1)) { /* peak -- % escapes (at least) one character */ char savec; @@ -736,19 +881,19 @@ process_expression(char *buff, char **bp, char const **str, safe_chr(savec, buff, bp); (*str)++; switch (savec) { - case '<': - savec = **str; - if (!savec) - goto exit_sequence; - for (savec = **str; savec && savec != '>'; savec = **str) { - safe_chr(savec, buff, bp); - (*str)++; - } - if(!savec) - goto exit_sequence; - safe_chr(savec, buff, bp); - (*str)++; - break; + case '<': + savec = **str; + if (!savec) + goto exit_sequence; + for (savec = **str; savec && savec != '>'; savec = **str) { + safe_chr(savec, buff, bp); + (*str)++; + } + if(!savec) + goto exit_sequence; + safe_chr(savec, buff, bp); + (*str)++; + break; case 'Q': case 'q': savec = **str; @@ -782,14 +927,10 @@ process_expression(char *buff, char **bp, char const **str, } break; } else { - char savec, nextc; - char *savepos; - ATTR *attrib; - (*str)++; savec = **str; if (!savec) { - /* Line ended in %, so treat it as a literal */ + /* Line ended in %, so treat it as literal */ safe_chr('%', buff, bp); goto exit_sequence; } @@ -797,27 +938,27 @@ process_expression(char *buff, char **bp, char const **str, (*str)++; switch (savec) { - case '%': /* %% - a real % */ + case '%': /* %% - a real % */ safe_chr('%', buff, bp); break; - case ' ': /* "% " for more natural typing */ + case ' ': /* "% " for more natural typing */ safe_str("% ", buff, bp); break; - case '!': /* executor dbref */ + case '!': /* executor dbref */ safe_dbref(executor, buff, bp); break; - case '@': /* caller dbref */ + case '@': /* caller dbref */ safe_dbref(caller, buff, bp); break; - case '#': /* enactor dbref */ + case '#': /* enactor dbref */ safe_dbref(enactor, buff, bp); break; - case ':': /* enactor unique id */ + case ':': /* enactor unique id */ safe_dbref(enactor, buff, bp); safe_chr(':', buff, bp); safe_integer(CreTime(enactor), buff, bp); break; - case '?': /* function limits */ + case '?': /* function limits */ if (pe_info) { safe_integer(pe_info->fun_invocations, buff, bp); safe_chr(' ', buff, bp); @@ -826,10 +967,10 @@ process_expression(char *buff, char **bp, char const **str, safe_str("0 0", buff, bp); } break; - case '~': /* enactor accented name */ + case '~': /* enactor accented name */ safe_str(accented_name(enactor), buff, bp); break; - case '+': /* argument count */ + case '+': /* argument count */ if (pe_info) safe_integer(pe_info->arg_count, buff, bp); else @@ -844,22 +985,22 @@ process_expression(char *buff, char **bp, char const **str, case '6': case '7': case '8': - case '9': /* positional argument */ + case '9': /* positional argument */ if (global_eval_context.wenv[savec - '0']) safe_str(global_eval_context.wenv[savec - '0'], buff, bp); break; case 'A': - case 'a': /* enactor absolute possessive pronoun */ + case 'a': /* enactor absolute possessive pronoun */ if (gender < 0) gender = get_gender(enactor); safe_str(absp[gender], buff, bp); break; case 'B': - case 'b': /* blank space */ + case 'b': /* blank space */ safe_chr(' ', buff, bp); break; case 'C': - case 'c': /* command line */ + case 'c': /* command line */ safe_str(global_eval_context.ccom, buff, bp); break; case 'I': @@ -868,7 +1009,7 @@ process_expression(char *buff, char **bp, char const **str, if (!nextc) goto exit_sequence; (*str)++; - if (!isdigit((unsigned char) nextc)) { + if (!isdigit((unsigned char) nextc)) { safe_str(T(e_int), buff, bp); break; } @@ -885,23 +1026,23 @@ process_expression(char *buff, char **bp, char const **str, safe_str(global_eval_context.ucom, buff, bp); break; case 'L': - case 'l': /* enactor location dbref */ + case 'l': /* enactor location dbref */ /* The security implications of this have * already been talked to death. Deal. */ safe_dbref(Location(enactor), buff, bp); break; case 'N': - case 'n': /* enactor name */ + case 'n': /* enactor name */ safe_str(Name(enactor), buff, bp); break; case 'O': - case 'o': /* enactor objective pronoun */ + case 'o': /* enactor objective pronoun */ if (gender < 0) gender = get_gender(enactor); safe_str(obj[gender], buff, bp); break; case 'P': - case 'p': /* enactor possessive pronoun */ + case 'p': /* enactor possessive pronoun */ if (gender < 0) gender = get_gender(enactor); safe_str(poss[gender], buff, bp); @@ -954,22 +1095,22 @@ process_expression(char *buff, char **bp, char const **str, if (global_eval_context.renv[qindex]) safe_str(global_eval_context.renv[qindex], buff, bp); } - break; - case 'R': - case 'r': /* newline */ + break; + case 'R': + case 'r': /* newline */ if (NEWLINE_ONE_CHAR) safe_chr('\n', buff, bp); else safe_str("\r\n", buff, bp); break; case 'S': - case 's': /* enactor subjective pronoun */ + case 's': /* enactor subjective pronoun */ if (gender < 0) gender = get_gender(enactor); safe_str(subj[gender], buff, bp); break; case 'T': - case 't': /* tab */ + case 't': /* tab */ safe_chr('\t', buff, bp); break; case 'V': @@ -977,7 +1118,7 @@ process_expression(char *buff, char **bp, char const **str, case 'W': case 'w': case 'X': - case 'x': /* attribute substitution */ + case 'x': /* attribute substitution */ nextc = **str; if (!nextc) goto exit_sequence; @@ -989,6 +1130,14 @@ process_expression(char *buff, char **bp, char const **str, if (attrib) safe_str(atr_value(attrib), buff, bp); break; + default: /* just copy */ + safe_chr(savec, buff, bp); + } + + if (isupper((unsigned char) savec)) + *savepos = UPCASE(*savepos); + } + break; case 'z': case 'Z': nextc = **str; @@ -1063,15 +1212,8 @@ process_expression(char *buff, char **bp, char const **str, } break; } - default: /* just copy */ - safe_chr(savec, buff, bp); - } - if (isupper((unsigned char) savec)) - *savepos = UPCASE(*savepos); - } - break; - case '{': /* "{}" parse group; recurse with no function check */ + case '{': /* "{}" parse group; recurse with no function check */ if (CALL_LIMIT && (pe_info->call_depth > CALL_LIMIT)) { (*str)++; break; @@ -1103,7 +1245,7 @@ process_expression(char *buff, char **bp, char const **str, /* Only strip one set of braces for commands */ eflags &= ~PE_COMMAND_BRACES; break; - case '[': /* "[]" parse group; recurse with mandatory function check */ + case '[': /* "[]" parse group; recurse with mandatory function check */ if (CALL_LIMIT && (pe_info->call_depth > CALL_LIMIT)) { (*str)++; break; @@ -1131,7 +1273,7 @@ process_expression(char *buff, char **bp, char const **str, (*str)++; } break; - case '(': /* Function call */ + case '(': /* Function call */ if (CALL_LIMIT && (pe_info->call_depth > CALL_LIMIT)) { (*str)++; break; @@ -1180,7 +1322,9 @@ process_expression(char *buff, char **bp, char const **str, for (sp = startpos, tp = name; sp < *bp; sp++) safe_chr(UPCASE(*sp), name, &tp); *tp = '\0'; - fp = func_hash_lookup(name); + fp = (eflags & PE_BUILTINONLY) ? builtin_func_hash_lookup(name) + : func_hash_lookup(name); + eflags &= ~PE_BUILTINONLY; /* Only applies to the outermost call */ if (!fp) { if (eflags & PE_FUNCTION_MANDATORY) { *bp = startpos; @@ -1218,10 +1362,12 @@ process_expression(char *buff, char **bp, char const **str, /* Check for the invocation limit */ if ((pe_info->fun_invocations >= FUNCTION_LIMIT) || (global_fun_invocations >= FUNCTION_LIMIT * 5)) { + const char *e_msg; + size_t e_len; e_msg = T(e_invoke); e_len = strlen(e_msg); if ((buff + e_len > *bp) || strcmp(e_msg, *bp - e_len)) - safe_str(e_msg, buff, bp); + safe_strl(e_msg, e_len, buff, bp); if (process_expression(name, &tp, str, executor, caller, enactor, PE_NOTHING, PT_PAREN, pe_info)) @@ -1255,6 +1401,7 @@ process_expression(char *buff, char **bp, char const **str, break; } denied = !check_func(executor, fp); + denied = denied || ((fp->flags & FN_USERFN) && !(eflags & PE_USERFN)); if (denied) temp_eflags &= ~(PE_COMPRESS_SPACES | PE_EVALUATE | PE_FUNCTION_CHECK); @@ -1267,20 +1414,18 @@ process_expression(char *buff, char **bp, char const **str, if (nfargs >= args_alloced) { char **nargs; int *narglens; - nargs = (char **) mush_malloc((nfargs + 10) * sizeof(char *), - "process_expression.function_arglist"); - narglens = (int *) mush_malloc((nfargs + 10) * sizeof(int), - "process_expression.function_arglens"); + nargs = mush_calloc(nfargs + 10, sizeof(char *), + "process_expression.function_arglist"); + narglens = mush_calloc(nfargs + 10, sizeof(int), + "process_expression.function_arglens"); for (j = 0; j < nfargs; j++) { nargs[j] = fargs[j]; narglens[j] = arglens[j]; } if (fargs != sargs) - mush_free((Malloc_t) fargs, - "process_expression.function_arglist"); + mush_free(fargs, "process_expression.function_arglist"); if (arglens != sarglens) - mush_free((Malloc_t) arglens, - "process_expression.function_arglens"); + mush_free(arglens, "process_expression.function_arglens"); fargs = nargs; arglens = narglens; args_alloced += 10; @@ -1316,7 +1461,7 @@ process_expression(char *buff, char **bp, char const **str, * Otherwise, return an error message. * Special case: zero args is recognized as one null arg. */ - if ((fp->minargs == 0 || (fp->minargs == 1 && (fp->flags & FN_ONEARG))) && (nfargs == 1) && (!*fargs[0] || arglens[0]== 0)) { + if ((fp->minargs == 0) && (nfargs == 1) && !*fargs[0]) { mush_free((Malloc_t) fargs[0], "process_expression.function_argument"); fargs[0] = NULL; @@ -1324,25 +1469,23 @@ process_expression(char *buff, char **bp, char const **str, nfargs = 0; } if ((nfargs < fp->minargs) || (nfargs > abs(fp->maxargs))) { - safe_str(T("#-1 FUNCTION ("), buff, bp); - safe_str(fp->name, buff, bp); - safe_str(") EXPECTS ", buff, bp); + safe_format(buff, bp, T("#-1 FUNCTION (%s) EXPECTS "), fp->name); if (fp->minargs == abs(fp->maxargs)) { safe_integer(fp->minargs, buff, bp); } else if ((fp->minargs + 1) == abs(fp->maxargs)) { safe_integer(fp->minargs, buff, bp); - safe_str(" OR ", buff, bp); + safe_str(T(" OR "), buff, bp); safe_integer(abs(fp->maxargs), buff, bp); } else if (fp->maxargs == INT_MAX) { - safe_str("AT LEAST ", buff, bp); + safe_str(T("AT LEAST "), buff, bp); safe_integer(fp->minargs, buff, bp); } else { - safe_str("BETWEEN ", buff, bp); + safe_str(T("BETWEEN "), buff, bp); safe_integer(fp->minargs, buff, bp); - safe_str(" AND ", buff, bp); + safe_str(T(" AND "), buff, bp); safe_integer(abs(fp->maxargs), buff, bp); } - safe_str(" ARGUMENTS BUT GOT ", buff, bp); + safe_str(T(" ARGUMENTS BUT GOT "), buff, bp); safe_integer(nfargs, buff, bp); } else { global_fun_recursions++; @@ -1387,17 +1530,12 @@ process_expression(char *buff, char **bp, char const **str, safe_chr('/', buff, bp); safe_str(userfn_tab[fp->where.offset].name, buff, bp); safe_chr(')', buff, bp); - } else { + } else { char *preserve[NUMQ]; - dbref local_ooref; if (fp->flags & FN_LOCALIZE) save_global_regs("@function.save", preserve); - /* Temporarily change ooref */ - local_ooref = ooref; - ooref = attrib->creator; do_userfn(buff, bp, thing, attrib, nfargs, fargs, - executor, caller, enactor, pe_info); - ooref = local_ooref; + executor, caller, enactor, pe_info, PE_USERFN); if (fp->flags & FN_LOCALIZE) restore_global_regs("@function.save", preserve); } diff --git a/src/pcre.c b/src/pcre.c index d66c8d3..c13cece 100644 --- a/src/pcre.c +++ b/src/pcre.c @@ -44,7 +44,13 @@ POSSIBILITY OF SUCH DAMAGE. /* Modified by Alan Schwartz for PennMUSH to change the use of * 'isblank' as a variable (reported to Philip Hazel for pcre 4.5) */ +#include #include "config.h" +#include "mypcre.h" + +/* Only use if a system libpcre isn't present. */ +#ifndef HAVE_PCRE + #include #include #include @@ -52,8 +58,6 @@ POSSIBILITY OF SUCH DAMAGE. #include #include #include -#include -#include "pcre.h" #include "confmagic.h" #undef min #undef max @@ -206,10 +210,10 @@ variable-length repeat, or a anything other than literal characters. */ /* Miscellaneous definitions */ -typedef int BOOL; +typedef bool BOOL; -#define FALSE 0 -#define TRUE 1 +#define FALSE false +#define TRUE true /* Escape items that are just an encoding of a particular data value. Note that ESC_n is defined as yet another macro, which is set in config.h to either \n @@ -928,14 +932,13 @@ Returns: the new block if is is indeed a byte-flipped regex NULL if it is not */ -real_pcre *_pcre_try_flipped(const real_pcre * re, real_pcre * internal_re, - const pcre_study_data * study, - pcre_study_data * internal_study); +real_pcre *_pcre_try_flipped(const real_pcre *re, real_pcre *internal_re, + const pcre_study_data *study, + pcre_study_data *internal_study); real_pcre * -_pcre_try_flipped(const real_pcre * re, real_pcre * internal_re, - const pcre_study_data * study, - pcre_study_data * internal_study) +_pcre_try_flipped(const real_pcre *re, real_pcre *internal_re, + const pcre_study_data *study, pcre_study_data *internal_study) { if (byteflip(re->magic_number, sizeof(re->magic_number)) != MAGIC_NUMBER) return NULL; @@ -1249,8 +1252,12 @@ Returns: if successful: 0 */ int - pcre_get_substring_list(const char *subject, int *ovector, int stringcount, - const char ***listptr); + + + + +pcre_get_substring_list(const char *subject, int *ovector, int stringcount, + const char ***listptr); int pcre_get_substring_list(const char *subject, int *ovector, int stringcount, @@ -1333,8 +1340,12 @@ Returns: if successful: */ int - pcre_get_substring(const char *subject, int *ovector, int stringcount, - int stringnumber, const char **stringptr); + + + + +pcre_get_substring(const char *subject, int *ovector, int stringcount, + int stringnumber, const char **stringptr); int pcre_get_substring(const char *subject, int *ovector, int stringcount, @@ -1384,9 +1395,13 @@ Returns: if successful: */ int - pcre_get_named_substring(const pcre * code, const char *subject, int *ovector, - int stringcount, const char *stringname, - const char **stringptr); + + + + +pcre_get_named_substring(const pcre * code, const char *subject, int *ovector, + int stringcount, const char *stringname, + const char **stringptr); int pcre_get_named_substring(const pcre * code, const char *subject, int *ovector, @@ -1561,7 +1576,7 @@ Returns: nothing */ static void -set_bit(uschar * start_bits, unsigned int c, BOOL caseless, compile_data * cd) +set_bit(uschar *start_bits, unsigned int c, BOOL caseless, compile_data *cd) { start_bits[c / 8] |= (1 << (c & 7)); if (caseless && (cd->ctypes[c] & ctype_letter) != 0) @@ -1589,8 +1604,8 @@ Returns: TRUE if table built, FALSE otherwise */ static BOOL -set_start_bits(const uschar * code, uschar * start_bits, BOOL caseless, - BOOL utf8, compile_data * cd) +set_start_bits(const uschar *code, uschar *start_bits, BOOL caseless, + BOOL utf8, compile_data *cd) { register int c; @@ -2265,6 +2280,10 @@ static const unsigned char ebcdic_chartab[] = { /* chartable partial dup */ /* Definition to allow mutual recursion */ static BOOL + + + + compile_regex(int, int, int *, uschar **, const uschar **, int *, BOOL, int, int *, int *, branch_chain *, compile_data *); @@ -2293,7 +2312,7 @@ Returns: zero or positive => a data character */ static int -check_escape(const uschar ** ptrptr, int *errorcodeptr, int bracount, +check_escape(const uschar **ptrptr, int *errorcodeptr, int bracount, int options, BOOL isclass) { const uschar *ptr = *ptrptr; @@ -2481,7 +2500,7 @@ Returns: value from ucp_type_table, or -1 for an invalid type */ static int -get_ucp(const uschar ** ptrptr, BOOL * negptr, int *errorcodeptr) +get_ucp(const uschar **ptrptr, BOOL *negptr, int *errorcodeptr) { int c, i, bot, top; const uschar *ptr = *ptrptr; @@ -2575,7 +2594,7 @@ Returns: TRUE or FALSE */ static BOOL -is_counted_repeat(const uschar * p) +is_counted_repeat(const uschar *p) { if ((digitab[*p++] & ctype_digit) == 0) return FALSE; @@ -2619,7 +2638,7 @@ Returns: pointer to '}' on success; */ static const uschar * -read_repeat_counts(const uschar * p, int *minp, int *maxp, int *errorcodeptr) +read_repeat_counts(const uschar *p, int *minp, int *maxp, int *errorcodeptr) { int min = 0; int max = -1; @@ -2686,7 +2705,7 @@ Returns: pointer to the first significant opcode */ static const uschar * -first_significant_code(const uschar * code, int *options, int optbit, +first_significant_code(const uschar *code, int *options, int optbit, BOOL skipassert) { for (;;) { @@ -2747,7 +2766,7 @@ Returns: the fixed length, or -1 if there is no fixed length, */ static int -find_fixedlength(uschar * code, int options) +find_fixedlength(uschar *code, int options) { int length = -1; @@ -2924,7 +2943,7 @@ Returns: pointer to the opcode for the bracket, or NULL if not found */ static const uschar * -find_bracket(const uschar * code, BOOL utf8, int number) +find_bracket(const uschar *code, BOOL utf8, int number) { utf8 = utf8; /* Stop pedantic compilers complaining */ @@ -2963,7 +2982,7 @@ Returns: pointer to the opcode for OP_RECURSE, or NULL if not found */ static const uschar * -find_recurse(const uschar * code, BOOL utf8) +find_recurse(const uschar *code, BOOL utf8) { utf8 = utf8; /* Stop pedantic compilers complaining */ @@ -3003,7 +3022,7 @@ Returns: TRUE if what is matched could be empty */ static BOOL -could_be_empty_branch(const uschar * code, const uschar * endcode, BOOL utf8) +could_be_empty_branch(const uschar *code, const uschar *endcode, BOOL utf8) { register int c; for (code = first_significant_code(code + 1 + LINK_SIZE, NULL, 0, TRUE); @@ -3129,8 +3148,8 @@ Returns: TRUE if what is matched could be empty */ static BOOL -could_be_empty(const uschar * code, const uschar * endcode, - branch_chain * bcptr, BOOL utf8) +could_be_empty(const uschar *code, const uschar *endcode, + branch_chain *bcptr, BOOL utf8) { while (bcptr != NULL && bcptr->current >= code) { if (!could_be_empty_branch(bcptr->current, endcode, utf8)) @@ -3160,8 +3179,7 @@ Returns: TRUE or FALSE */ static BOOL -check_posix_syntax(const uschar * ptr, const uschar ** endptr, - compile_data * cd) +check_posix_syntax(const uschar *ptr, const uschar **endptr, compile_data *cd) { int terminator; /* Don't combine these lines; the Solaris cc */ terminator = *(++ptr); /* compiler warns about "non-constant" initializer. */ @@ -3194,7 +3212,7 @@ Returns: a value representing the name, or -1 if unknown */ static int -check_posix_name(const uschar * ptr, int len) +check_posix_name(const uschar *ptr, int len) { register int yield = 0; while (posix_name_lengths[yield] != 0) { @@ -3231,7 +3249,7 @@ Returns: nothing */ static void -adjust_recurse(uschar * group, int adjust, BOOL utf8, compile_data * cd) +adjust_recurse(uschar *group, int adjust, BOOL utf8, compile_data *cd) { uschar *ptr = group; while ((ptr = (uschar *) find_recurse(ptr, utf8)) != NULL) { @@ -3260,7 +3278,7 @@ Returns: new code pointer */ static uschar * -auto_callout(uschar * code, const uschar * ptr, compile_data * cd) +auto_callout(uschar *code, const uschar *ptr, compile_data *cd) { *code++ = OP_CALLOUT; *code++ = 255; @@ -3288,8 +3306,7 @@ Returns: nothing */ static void -complete_callout(uschar * previous_callout, const uschar * ptr, - compile_data * cd) +complete_callout(uschar *previous_callout, const uschar *ptr, compile_data *cd) { int length = ptr - cd->start_pattern - GET(previous_callout, 2); PUT(previous_callout, 2 + LINK_SIZE, length); @@ -3371,9 +3388,9 @@ Returns: TRUE on success */ static BOOL -compile_branch(int *optionsptr, int *brackets, uschar ** codeptr, - const uschar ** ptrptr, int *errorcodeptr, int *firstbyteptr, - int *reqbyteptr, branch_chain * bcptr, compile_data * cd) +compile_branch(int *optionsptr, int *brackets, uschar **codeptr, + const uschar **ptrptr, int *errorcodeptr, int *firstbyteptr, + int *reqbyteptr, branch_chain *bcptr, compile_data *cd) { int repeat_type, op_type; int repeat_min = 0, repeat_max = 0; /* To please picky compilers */ @@ -5000,10 +5017,10 @@ Returns: TRUE on success */ static BOOL -compile_regex(int options, int oldims, int *brackets, uschar ** codeptr, - const uschar ** ptrptr, int *errorcodeptr, BOOL lookbehind, +compile_regex(int options, int oldims, int *brackets, uschar **codeptr, + const uschar **ptrptr, int *errorcodeptr, BOOL lookbehind, int skipbytes, int *firstbyteptr, int *reqbyteptr, - branch_chain * bcptr, compile_data * cd) + branch_chain *bcptr, compile_data *cd) { const uschar *ptr = *ptrptr; uschar *code = *codeptr; @@ -5201,7 +5218,7 @@ Returns: TRUE or FALSE */ static BOOL -is_anchored(register const uschar * code, int *options, +is_anchored(register const uschar *code, int *options, unsigned int bracket_map, unsigned int backref_map) { do { @@ -5273,7 +5290,7 @@ Returns: TRUE or FALSE */ static BOOL -is_startline(const uschar * code, unsigned int bracket_map, +is_startline(const uschar *code, unsigned int bracket_map, unsigned int backref_map) { do { @@ -5344,7 +5361,7 @@ Returns: -1 or the fixed first char */ static int -find_firstassertedchar(const uschar * code, int *options, BOOL inassert) +find_firstassertedchar(const uschar *code, int *options, BOOL inassert) { register int c = -1; do { @@ -6505,7 +6522,7 @@ Returns: TRUE if matched */ static BOOL -match_ref(int offset, register const uschar * eptr, int length, match_data * md, +match_ref(int offset, register const uschar *eptr, int length, match_data *md, unsigned long int ims) { const uschar *p = md->start_subject + md->offset_vector[offset]; @@ -6717,8 +6734,8 @@ Returns: MATCH_MATCH if matched ) these values are >= 0 */ static int -match(REGISTER const uschar * eptr, REGISTER const uschar * ecode, - int offset_top, match_data * md, unsigned long int ims, eptrblock * eptrb, +match(REGISTER const uschar *eptr, REGISTER const uschar *ecode, + int offset_top, match_data *md, unsigned long int ims, eptrblock *eptrb, int flags) { /* These variables do not need to be preserved over recursion in this function, @@ -9222,3 +9239,28 @@ the loop runs just once. */ } /* End of pcre_exec.c */ + +#endif /* !HAVE_PCRE */ + +/** Return a default pcre_extra pointer pointing to a static region + set up to use a fairly low match-limit setting. +*/ +struct pcre_extra * +default_match_limit(void) +{ + static struct pcre_extra ex; + memset(&ex, 0, sizeof ex); + set_match_limit(&ex); + return &ex; +} + + +/** Set a low match-limit setting in an existing pcre_extra struct. */ +void +set_match_limit(struct pcre_extra *ex) +{ + if (!ex) + return; + ex->flags |= PCRE_EXTRA_MATCH_LIMIT; + ex->match_limit = PENN_MATCH_LIMIT; +} diff --git a/src/player.c b/src/player.c index 6ebdeb0..7707c74 100644 --- a/src/player.c +++ b/src/player.c @@ -16,6 +16,9 @@ #include #ifdef I_SYS_TIME #include +#ifdef TIME_WITH_SYS_TIME +#include +#endif #else #include #endif @@ -272,13 +275,13 @@ create_player(const char *name, const char *password, const char *host, /* The HAS_SENDMAIL ifdef is kept here as a hint to metaconfig */ #ifdef MAILER -#undef HAS_SENDMAIL -#define HAS_SENDMAIL 1 +#undef HAVE_SENDMAIL +#define HAVE_SENDMAIL 1 #undef SENDMAIL #define SENDMAIL MAILER #endif -#ifdef HAS_SENDMAIL +#ifdef HAVE_SENDMAIL /** Size of the elems array */ #define NELEMS (sizeof(elems)-1) @@ -402,12 +405,14 @@ email_register_player(const char *name, const char *email, const char *host, #else dbref email_register_player(const char *name, const char *email, const char *host, - const char *ip) + const char *ip __attribute__ ((__unused__))) { do_log(LT_CONN, 0, 0, T("Failed registration (no sendmail) from %s"), host); + do_log(LT_CONN, 0, 0, T("Requested character: '%s'. Email address: %s\n"), + name, email); return NOTHING; } -#endif +#endif /* !HAVE_SENDMAIL */ static dbref make_player(const char *name, const char *password, const char *host, @@ -416,7 +421,7 @@ make_player(const char *name, const char *password, const char *host, dbref player; char temp[SBUF_LEN]; - object_flag_type flags; + /* object_flag_type flags; Unused apparently */ struct module_entry_t *m; void (*handle)(dbref player); @@ -455,10 +460,11 @@ make_player(const char *name, const char *password, const char *host, add_player(player); add_lock(GOD, player, Basic_Lock, parse_boolexp(player, "=me", Basic_Lock), - -1); + LF_DEFAULT); add_lock(GOD, player, Enter_Lock, parse_boolexp(player, "=me", Basic_Lock), - -1); - add_lock(GOD, player, Use_Lock, parse_boolexp(player, "=me", Basic_Lock), -1); + LF_DEFAULT); + add_lock(GOD, player, Use_Lock, parse_boolexp(player, "=me", Basic_Lock), + LF_DEFAULT); current_state.players++; diff --git a/src/plyrlist.c b/src/plyrlist.c index 1638c5a..fc5da19 100644 --- a/src/plyrlist.c +++ b/src/plyrlist.c @@ -15,17 +15,20 @@ #include "copyrite.h" #include "conf.h" #include "externs.h" +#include "attrib.h" #include "mushdb.h" #include "dbdefs.h" #include "attrib.h" #include "flags.h" #include "attrib.h" #include "htab.h" +#include "mymalloc.h" #include "confmagic.h" /** Hash table of player names */ HASHTAB htab_player_list; +slab *player_dbref_slab = NULL; static int hft_initialized = 0; static void init_hft(void); @@ -35,14 +38,15 @@ static void delete_dbref(void *); static void delete_dbref(void *data) { - mush_free(data, "plyrlist.entry"); + slab_free(player_dbref_slab, data); } static void init_hft(void) { - hash_init(&htab_player_list, 256, sizeof(dbref), delete_dbref); + hash_init(&htab_player_list, 256, delete_dbref); + player_dbref_slab = slab_create("player list dbrefs", sizeof(dbref)); hft_initialized = 1; } @@ -66,7 +70,7 @@ add_player(dbref player) dbref *p; if (!hft_initialized) init_hft(); - p = mush_malloc(sizeof *p, "plyrlist.entry"); + p = slab_malloc(player_dbref_slab, NULL); if (!p) mush_panic(T("Unable to allocate memory in plyrlist!")); *p = player; @@ -90,8 +94,7 @@ add_player_alias(dbref player, const char *alias) add_player(player); return; } - strncpy(tbuf1, alias, BUFFER_LEN - 1); - tbuf1[BUFFER_LEN - 1] = '\0'; + mush_strncpy(tbuf1, alias, BUFFER_LEN); s = trim_space_sep(tbuf1, ALIAS_DELIMITER); while (s) { sp = split_token(&s, ALIAS_DELIMITER); @@ -157,8 +160,7 @@ delete_player(dbref player, const char *alias) * them all, but we shouldn't delete the player's own name! */ char tbuf1[BUFFER_LEN], *s, *sp; - strncpy(tbuf1, alias, BUFFER_LEN - 1); - tbuf1[BUFFER_LEN - 1] = '\0'; + mush_strncpy(tbuf1, alias, BUFFER_LEN); s = trim_space_sep(tbuf1, ALIAS_DELIMITER); while (s) { sp = split_token(&s, ALIAS_DELIMITER); @@ -166,7 +168,7 @@ delete_player(dbref player, const char *alias) sp++; if (sp && *sp) { dbref *p; - p = mush_malloc(sizeof *p, "plyrlist.entry"); + p = slab_malloc(player_dbref_slab, NULL); if (!p) mush_panic(T("Unable to allocate memory in plyrlist!")); *p = player; @@ -197,8 +199,7 @@ reset_player_list(dbref player, const char *oldname, const char *oldalias, name = Name(player); } if (oldalias) { - strncpy(tbuf1, oldalias, BUFFER_LEN - 1); - tbuf1[BUFFER_LEN - 1] = '\0'; + mush_strncpy(tbuf1, oldalias, BUFFER_LEN); if (alias) { strncpy(tbuf2, alias, BUFFER_LEN - 1); tbuf2[BUFFER_LEN - 1] = '\0'; @@ -212,8 +213,7 @@ reset_player_list(dbref player, const char *oldname, const char *oldalias, */ ATTR *a = atr_get_noparent(player, "ALIAS"); if (a) { - strncpy(tbuf1, atr_value(a), BUFFER_LEN - 1); - tbuf1[BUFFER_LEN - 1] = '\0'; + mush_strncpy(tbuf1, atr_value(a), BUFFER_LEN); } else { tbuf1[0] = '\0'; } diff --git a/src/portmsg.c b/src/portmsg.c index fea0109..63c197d 100644 --- a/src/portmsg.c +++ b/src/portmsg.c @@ -59,68 +59,64 @@ #ifdef I_SYS_TYPES #include #endif +#ifdef I_SYS_STAT #include +#endif +#ifdef I_SYS_FILE #include +#endif #include #include -#ifdef I_SYS_ERRNO -#include -#endif +#ifdef I_SYS_SOCKET #include +#endif +#ifdef I_NETINET_IN #include +#endif +#ifdef I_SYS_PARAM #include +#endif #include -#ifdef I_SYS_WAIT +#ifdef HAVE_SYS_WAIT_H #include #endif +#ifdef I_FCNTL #include +#endif #include +#include #include "conf.h" #include "externs.h" #include "mysocket.h" -#include "confmagic.h" - -#ifdef HAS_WAITPID -#define WAIT_TYPE int -#else -#ifdef UNION_WAIT -#define WAIT_TYPE union wait -#else -#define WAIT_TYPE int -#endif -#endif +#include "wait.h" #ifndef SINGLE_IP_ADDR const char *host_ip = ""; #else -const char *host_ip = SINGLE_IP_ADDR +const char *host_ip = SINGLE_IP_ADDR; #endif - static void wait_on_child(int sig); + +static void wait_on_child(int sig); static void lostconn(int sig) NORETURN; enum { MAX_CONNECTIONS = 15 }; - int connections = 0; + sig_atomic_t connections = 0; static void - wait_on_child(int sig __attribute__ ((__unused__))) + wait_on_child(int sig) { WAIT_TYPE status; -#ifdef HAS_WAITPID - while (waitpid(-1, &status, WNOHANG) > 0) - connections--; -#else - while (wait3(&status, WNOHANG, NULL) > 0) + while (mush_wait(0, &status, WNOHANG) > 0) connections--; -#endif if (connections < 0) connections = 0; - reload_sig_handler(SIGCHLD, wait_on_child); + reload_sig_handler(sig, wait_on_child); } void @@ -132,7 +128,7 @@ lostconn(int sig __attribute__ ((__unused__))) int main(int argc, char **argv) { - int msgfd, fd; + int msgfd; struct stat statBuf; Port_t port; char *msg; @@ -176,15 +172,12 @@ main(int argc, char **argv) default: return 0; } -#ifdef HAS_SETPGRP -#ifdef USE_BSD_SETPGRP - if (setpgrp(0, getpid()) == -1) { +#ifdef HAVE_SETSID + if (setsid() < 0) + perror("Unable to create new session id (Harmless)"); #else - if (setpgrp() == -1) { -#endif - perror("can't change process group"); - return 1; - } + if (new_process_group() < 0) + perror("Unable to set new process group (Probably harmless)"); #endif #ifdef USE_TIOCNOTTY @@ -196,7 +189,7 @@ main(int argc, char **argv) install_sig_handler(SIGCHLD, wait_on_child); - if ((sockfd = make_socket(port, NULL, NULL, host_ip)) < 0) { + if ((sockfd = make_socket(port, SOCK_STREAM, NULL, NULL, host_ip)) < 0) { perror("can't make socket"); return 1; } @@ -234,3 +227,10 @@ main_again: return 0; } + +/* Wrappers for perror */ +void +penn_perror(const char *err) +{ + fprintf(stderr, "portmsg: %s: %s\n", err, strerror(errno)); +} diff --git a/src/predicat.c b/src/predicat.c index e6bf9dd..9cda25c 100644 --- a/src/predicat.c +++ b/src/predicat.c @@ -18,6 +18,9 @@ #endif #ifdef I_SYS_TIME #include +#ifdef TIME_WITH_SYS_TIME +#include +#endif #else #include #endif @@ -128,7 +131,7 @@ charge_action(dbref player, dbref thing, const char *awhat) return res; } else { /* no charges left, try to execute runout */ - return queue_attribute(thing, "RUNOUT", 0); + return queue_attribute(thing, "RUNOUT", player); } } } @@ -1104,7 +1107,7 @@ do_switch(dbref player, char *expression, char **argv, dbref cause, * \return matching dbref or NOTHING or AMBIGUOUS. */ dbref -parse_match_possessor(dbref player, const char **str) +parse_match_possessor(dbref player, char **str) { const char *box; /* name of container */ char *obj; /* name of object */ @@ -1411,7 +1414,7 @@ grep_helper(dbref player, dbref thing __attribute__ ((__unused__)), strncpy(buf, s, gh->len); buf[gh->len] = '\0'; s += gh->len; - safe_format(tbuf1, &tbp, "%s%s%s", ANSI_HILITE, buf, ANSI_NORMAL); + safe_format(tbuf1, &tbp, "%s%s%s", ANSI_HILITE, buf, ANSI_END); } else { safe_chr(*s, tbuf1, &tbp); s++; @@ -1425,7 +1428,7 @@ grep_helper(dbref player, dbref thing __attribute__ ((__unused__)), ANSI_HILITE, AL_NAME(atr), Owner(AL_CREATOR(atr)), privs_to_letters(attr_privs_view, AL_FLAGS(atr)), - ANSI_NORMAL, tbuf1); + ANSI_END, tbuf1); return found; } diff --git a/src/privtab.c b/src/privtab.c index 160e0d7..838af7c 100644 --- a/src/privtab.c +++ b/src/privtab.c @@ -10,10 +10,12 @@ #include "copyrite.h" #include "config.h" +#include #include #include #include #include "conf.h" +#include "mushtype.h" #include "privtab.h" #include "externs.h" #include "confmagic.h" @@ -30,16 +32,16 @@ * \param origprivs the original privileges. * \return a privilege bitmask. */ -int -string_to_privs(PRIV *table, const char *str, long int origprivs) +privbits +string_to_privs(PRIV *table, const char *str, privbits origprivs) { PRIV *c; - long int yes = 0; - long int no = 0; - long int ltr = 0; + privbits yes = 0; + privbits no = 0; + privbits ltr = 0; char *p, *r; char tbuf1[BUFFER_LEN]; - int not; + bool not; int words = 0; if (!str || !*str) @@ -95,15 +97,15 @@ string_to_privs(PRIV *table, const char *str, long int origprivs) * \param origprivs the original privileges. * \return a privilege bitmask. */ -int -list_to_privs(PRIV *table, const char *str, long int origprivs) -{ +privbits +list_to_privs(PRIV *table, const char *str, privbits origprivs) +{ PRIV *c; - long int yes = 0; - long int no = 0; + privbits yes = 0; + privbits no = 0; char *p, *r; char tbuf1[BUFFER_LEN]; - int not; + bool not; int words = 0; if (!str || !*str) @@ -143,13 +145,14 @@ list_to_privs(PRIV *table, const char *str, long int origprivs) * \retval -1 string at least one name matched no privs. */ int -string_to_privsets(PRIV *table, const char *str, int *setprivs, int *clrprivs) +string_to_privsets(PRIV *table, const char *str, privbits *setprivs, + privbits *clrprivs) { PRIV *c; char *p, *r; char tbuf1[BUFFER_LEN]; - int not; - long int ltr; + bool not; + privbits ltr; int words = 0; int err = 0; int found = 0; @@ -207,13 +210,13 @@ string_to_privsets(PRIV *table, const char *str, int *setprivs, int *clrprivs) * \param origprivs the original privileges. * \return a privilege bitmask. */ -int -letter_to_privs(PRIV *table, const char *str, long int origprivs) +privbits +letter_to_privs(PRIV *table, const char *str, privbits origprivs) { PRIV *c; - long int yes = 0, no = 0; + privbits yes = 0, no = 0; const char *p; - int not; + bool not; if (!str || !*str) return origprivs; @@ -244,7 +247,7 @@ letter_to_privs(PRIV *table, const char *str, long int origprivs) * \return statically allocated space-separated string of priv names. */ const char * -privs_to_string(PRIV *table, int privs) +privs_to_string(PRIV *table, privbits privs) { PRIV *c; static char buf[BUFFER_LEN]; @@ -270,7 +273,7 @@ privs_to_string(PRIV *table, int privs) * \return statically allocated string of priv letters. */ const char * -privs_to_letters(PRIV *table, int privs) +privs_to_letters(PRIV *table, privbits privs) { PRIV *c; static char buf[BUFFER_LEN]; diff --git a/src/prog.c b/src/prog.c index 064f9aa..eb1b52e 100644 --- a/src/prog.c +++ b/src/prog.c @@ -4,11 +4,8 @@ */ #include "copyrite.h" #include "config.h" -#ifdef I_STRING #include -#else #include -#endif #include "conf.h" #include "externs.h" #include "parse.h" @@ -596,9 +593,6 @@ pw_player_connect(DESC * d, char *input __attribute__ ((__unused__))) add_to_exit_path(d, d->player); announce_disconnect(d->player); d->player = d->pinfo.object; -#ifdef USE_MAILER - d->mailp = (MAIL *) find_exact_starting_point(d->pinfo.object); -#endif /* We're good @su him */ is_hidden = Can_Hide(d->pinfo.object) && Dark(d->pinfo.object); DESC_ITER_CONN(match) diff --git a/src/ptab.c b/src/ptab.c index dd05010..4b28a69 100644 --- a/src/ptab.c +++ b/src/ptab.c @@ -35,7 +35,8 @@ ptab_init(PTAB *tab) { if (!tab) return; - tab->state = tab->maxlen = tab->len = tab->current = 0; + tab->state = 0; + tab->maxlen = tab->len = tab->current = 0; tab->tab = NULL; } @@ -48,13 +49,14 @@ ptab_free(PTAB *tab) if (!tab) return; if (tab->tab) { - int n; + size_t n; for (n = 0; n < tab->len; n++) mush_free(tab->tab[n], "ptab.entry"); mush_free(tab->tab, "ptab"); } tab->tab = NULL; - tab->state = tab->maxlen = tab->len = tab->current = 0; + tab->state = 0; + tab->maxlen = tab->len = tab->current = 0; } /** Search a ptab for an entry that prefix-matches a given key. @@ -67,7 +69,7 @@ ptab_free(PTAB *tab) void * ptab_find(PTAB *tab, const char *key) { - int nun; + size_t nun; if (!tab || !key || !*key || tab->state) return NULL; @@ -82,9 +84,9 @@ ptab_find(PTAB *tab, const char *key) } } } else { /* Binary search of the index */ - int left = 0; + size_t left = 0; int cmp; - int right = tab->len - 1; + size_t right = tab->len - 1; while (1) { nun = (left + right) / 2; @@ -98,9 +100,10 @@ ptab_find(PTAB *tab, const char *key) return tab->tab[nun]->data; } else if (cmp < 0) { int mem; + size_t mem2; /* We need to catch the first unique prefix */ if (string_prefix(tab->tab[nun]->key, key)) { - for (mem = nun - 1; mem >= 0; mem--) { + for (mem = (int) nun - 1; mem >= 0; mem--) { if (string_prefix(tab->tab[mem]->key, key)) { if (strcasecmp(tab->tab[mem]->key, key) == 0) return tab->tab[mem]->data; @@ -108,21 +111,23 @@ ptab_find(PTAB *tab, const char *key) break; } /* Non-unique prefix */ - if (mem != nun - 1) + if (mem != (int) nun - 1) return NULL; - for (mem = nun + 1; mem < tab->len; mem++) { - if (string_prefix(tab->tab[mem]->key, key)) { - if (strcasecmp(tab->tab[mem]->key, key) == 0) - return tab->tab[mem]->data; + for (mem2 = nun + 1; mem2 < tab->len; mem2++) { + if (string_prefix(tab->tab[mem2]->key, key)) { + if (strcasecmp(tab->tab[mem2]->key, key) == 0) + return tab->tab[mem2]->data; } else break; } - if (mem != nun + 1) + if (mem2 != nun + 1) return NULL; return tab->tab[nun]->data; } if (left == right) break; + if (nun == 0) + break; right = nun - 1; } else { /* cmp > 0 */ if (left == right) @@ -155,7 +160,7 @@ ptab_find_exact(PTAB *tab, const char *key) static int ptab_find_exact_nun(PTAB *tab, const char *key) { - int nun; + size_t nun; if (!tab || !key || tab->state) return -1; @@ -165,14 +170,14 @@ ptab_find_exact_nun(PTAB *tab, const char *key) for (nun = 0; nun < tab->len; nun++) { cmp = strcasecmp(tab->tab[nun]->key, key); if (cmp == 0) - return nun; + return (int) nun; else if (cmp > 0) return -1; } } else { /* Binary search of the index */ - int left = 0; + size_t left = 0; int cmp; - int right = tab->len - 1; + size_t right = tab->len - 1; while (1) { nun = (left + right) / 2; @@ -183,12 +188,14 @@ ptab_find_exact_nun(PTAB *tab, const char *key) cmp = strcasecmp(key, tab->tab[nun]->key); if (cmp == 0) - return nun; + return (int) nun; if (left == right) break; - if (cmp < 0) + if (cmp < 0) { + if (nun == 0) + break; right = nun - 1; - else /* cmp > 0 */ + } else /* cmp > 0 */ left = nun + 1; } } @@ -196,15 +203,17 @@ ptab_find_exact_nun(PTAB *tab, const char *key) } static void -delete_entry(PTAB *tab, int n) +delete_entry(PTAB *tab, size_t n) { mush_free(tab->tab[n], "ptab.entry"); + if (tab->len == 0) + return; /* If we're deleting the last item in the list, just decrement the length. * Otherwise, we have to fill in the hole */ if (n < tab->len - 1) { - int i; + size_t i; for (i = n + 1; i < tab->len; i++) tab->tab[i - 1] = tab->tab[i]; } @@ -221,7 +230,7 @@ ptab_delete(PTAB *tab, const char *key) int nun; nun = ptab_find_exact_nun(tab, key); if (nun >= 0) - delete_entry(tab, nun); + delete_entry(tab, (size_t) nun); return; } @@ -264,7 +273,37 @@ ptab_end_inserts(PTAB *tab) tab->maxlen = tab->len + 10; } -/** Insert an entry into a ptab. +/** Grow a table */ +static void +ptab_grow(PTAB *tab) +{ + struct ptab_entry **tmp; + size_t oldmaxlen; + + if (!tab) + return; + + oldmaxlen = tab->maxlen; + + if (tab->maxlen == 0) + tab->maxlen = 200; + else + tab->maxlen *= 2; + tmp = realloc(tab->tab, tab->maxlen * sizeof(struct ptab_entry **)); + if (tab->tab == NULL) + add_check("ptab"); + if (!tmp) { + tab->maxlen = oldmaxlen; + return; + } + memset(tmp + tab->len, 0, tab->maxlen - tab->len); + tab->tab = tmp; +} + +/** Insert an entry into a ptab. This needs to be bracketed between + * calls to ptab_start_inserts() and ptab_end_inserts(), and is meant + * for mass additions to the table. To insert a single isolated entry, + * see ptab_insert_one(). * \param tab pointer to a ptab. * \param key key to insert entry under. * \param data pointer to entry data. @@ -272,24 +311,13 @@ ptab_end_inserts(PTAB *tab) void ptab_insert(PTAB *tab, const char *key, void *data) { - int lamed; + size_t lamed; if (!tab || tab->state != 1) return; - if (tab->len == tab->maxlen) { - struct ptab_entry **tmp; - if (tab->maxlen == 0) - tab->maxlen = 200; - else - tab->maxlen *= 2; - tmp = realloc(tab->tab, tab->maxlen * sizeof(struct ptab_entry **)); - if (tab->tab == NULL) - add_check("ptab"); - if (!tmp) - return; - tab->tab = tmp; - } + if (tab->len >= tab->maxlen) + ptab_grow(tab); lamed = strlen(key) + 1; @@ -301,6 +329,57 @@ ptab_insert(PTAB *tab, const char *key, void *data) } +/** Insert an entry into a ptab. This should be used for inserting single + * entries. To insert multiple entries at a time, see ptab_insert(). + * \param tab the table + * \param key the key + * \param data data pointer + */ +void +ptab_insert_one(PTAB *tab, const char *key, void *data) +{ + size_t len, n; + + if (!tab) + return; + + if (tab->state) { + /* In the middle of a ptab_start_inserts()/ptab_end_inserts() block */ + ptab_insert(tab, key, data); + return; + } + + if (tab->len + 1 >= tab->maxlen) + ptab_grow(tab); + + /* Figure out where to insert at */ + for (n = 0; n < tab->len; n++) { + int m = strcasecmp(tab->tab[n]->key, key); + if (m == 0) /* Duplicate entry. */ + return; + else if (m > 0) + break; + } + + /* Move everything after the location down one */ + if (n < tab->len) { + size_t m; + for (m = tab->len - 1; m >= n; m--) { + tab->tab[m + 1] = tab->tab[m]; + if (m == 0) + break; + } + } + + /* And splice in the new one */ + len = strlen(key) + 1; + tab->tab[n] = mush_malloc(PTAB_SIZE + len, "ptab.entry"); + tab->tab[n]->data = data; + memcpy(tab->tab[n]->key, key, len); + tab->len++; + +} + /** Return the data (and optionally the key) of the first entry in a ptab. * This function resets the 'current' index in the ptab to the start * of the table. @@ -352,13 +431,13 @@ ptab_stats_header(dbref player) void ptab_stats(dbref player, PTAB *tab, const char *pname) { - int mem, nun; + size_t mem, nun; mem = sizeof(struct ptab_entry *) * tab->maxlen; for (nun = 0; nun < tab->len; nun++) mem += PTAB_SIZE + strlen(tab->tab[nun]->key) + 1; - notify_format(player, "%-10s %7d %14.3f %39d", pname, tab->len, log(tab->len), - mem); + notify_format(player, "%-10s %7d %14.3f %39d", pname, (int) tab->len, + log((double) tab->len), (int) mem); } diff --git a/src/rob.c b/src/rob.c index 32b137c..92edb73 100644 --- a/src/rob.c +++ b/src/rob.c @@ -309,8 +309,7 @@ do_buy(dbref player, char *item, char *from, int price) a = atr_get(vendor, "PRICELIST"); if (!a) continue; - strncpy(prices, atr_value(a), BUFFER_LEN); - prices[BUFFER_LEN - 1] = '\0'; + mush_strncpy(prices, atr_value(a), BUFFER_LEN); upcasestr(prices); count = list2arr(r, BUFFER_LEN / 2, prices, ' '); if (!count) @@ -412,8 +411,8 @@ do_buy(dbref player, char *item, char *from, int price) void s_Pennies(dbref thing, int amnt) { - if(amnt > HUGE_INT) - Pennies(thing) = (int) HUGE_INT; + if(amnt > MAX_PENNIES) + Pennies(thing) = (int) MAX_PENNIES; else if(amnt < 0) Pennies(thing) = 0; else Pennies(thing) = amnt; diff --git a/src/services.c b/src/services.c index cb84325..35511fa 100644 --- a/src/services.c +++ b/src/services.c @@ -30,7 +30,7 @@ #define THIS_SERVICE_DISPLAY "CobraMUSH for Win32" int WIN32_CDECL main(int argc, char **argv); -void mainthread(int argc, char **argv); +int mainthread(int argc, char **argv); SERVICE_STATUS ssStatus; /* current status of the service */ @@ -68,9 +68,7 @@ int WIN32_CDECL service_error(DWORD error_code, char *themessage, ...); int WIN32_CDECL -main(argc, argv) - int argc; - char **argv; +main(int argc, char **argv) { SERVICE_TABLE_ENTRY dispatchTable[] = { @@ -433,7 +431,7 @@ worker_thread(VOID * notused) /* start up the main MUSH code */ - mainthread(argc, argv); + exit(mainthread(argc, argv)); } /* end of worker_thread */ diff --git a/src/set.c b/src/set.c index 2f378fc..fd5f61e 100644 --- a/src/set.c +++ b/src/set.c @@ -13,6 +13,9 @@ #include #ifdef I_SYS_TIME #include +#ifdef TIME_WITH_SYS_TIME +#include +#endif #else #include #endif @@ -60,7 +63,7 @@ void do_name(dbref player, const char *name, char *newname) { dbref thing; - char *password; + char *eon; /* End Of Name */ char *myenv[10]; int i; @@ -74,45 +77,26 @@ do_name(dbref player, const char *name, char *newname) } /* check for renaming a player */ if (IsPlayer(thing)) { - if (PLAYER_NAME_SPACES) { - if (*newname == '\"') { - for (; *newname && ((*newname == '\"') - || isspace((unsigned char) *newname)); - newname++) ; - password = newname; - while (*password && (*password != '\"')) { - while (*password && (*password != '\"')) - password++; - if (*password == '\"') { - *password++ = '\0'; - while (*password && isspace((unsigned char) *password)) - password++; - break; - } - } - } else { - password = newname; - while (*password && !isspace((unsigned char) *password)) - password++; - if (*password) { - *password++ = '\0'; - while (*password && isspace((unsigned char) *password)) - password++; + if (*newname == '"') { + for (; *newname && ((*newname == '"') + || isspace((unsigned char) *newname)); newname++) ; + eon = newname; + while (*eon && (*eon != '"')) { + while (*eon && (*eon != '"')) + eon++; + if (*eon == '"') { + *eon++ = '\0'; + while (*eon && isspace((unsigned char) *eon)) + eon++; + break; } } } else { - - /* split off password */ - for (password = newname + strlen(newname) - 1; - *password && !isspace((unsigned char) *password); password--) ; - for (; *password && isspace((unsigned char) *password); password--) ; - /* eat whitespace */ - if (*password) { - *++password = '\0'; /* terminate name */ - password++; - while (*password && isspace((unsigned char) *password)) - password++; - } + eon = newname; + while (*eon && !isspace((unsigned char) *eon)) + eon++; + if (*eon) + *eon++ = '\0'; } if (!ok_player_name(newname, player, thing)) { notify(player, T("You can't give a player that name.")); @@ -132,8 +116,7 @@ do_name(dbref player, const char *name, char *newname) /* everything ok, change the name */ myenv[0] = (char *) mush_malloc(BUFFER_LEN, "string"); myenv[1] = (char *) mush_malloc(BUFFER_LEN, "string"); - strncpy(myenv[0], Name(thing), BUFFER_LEN - 1); - myenv[0][BUFFER_LEN - 1] = '\0'; + mush_strncpy(myenv[0], Name(thing), BUFFER_LEN); strcpy(myenv[1], newname); for (i = 2; i < 10; i++) myenv[i] = NULL; @@ -174,13 +157,11 @@ do_chown(dbref player, const char *name, const char *newobj, int preserve) { dbref thing; dbref newowner = NOTHING; - char *sp; long match_flags = MAT_POSSESSION | MAT_HERE | MAT_EXIT | MAT_ABSOLUTE; /* check for '@chown /=' */ - sp = strchr(name, '/'); - if (sp) { + if (strchr(name, '/')) { do_atrchown(player, name, newobj); return; } @@ -450,8 +431,8 @@ do_chzone(dbref player, char const *name, char const *newobj, int noisy) /** Structure for af_helper() data. */ struct af_args { - int setf; /**< flag bits to set */ - int clrf; /**< flag bits to clear */ + privbits setf; /**< flag bits to set */ + privbits clrf; /**< flag bits to clear */ char *setflags; /**< list of names of flags to set */ char *clrflags; /**< list of names of flags to clear */ }; @@ -558,26 +539,46 @@ do_attrib_flags(dbref player, const char *obj, const char *atrname, * \retval 0 failure to set. */ int -do_set(dbref player, const char *name, char *flag) +do_set(dbref player, const char *xname, char *flag) { dbref thing; int her, listener, negate; - char *p, *f; + char *p, *f, *name; char flagbuff[BUFFER_LEN]; + if (!xname || !*xname) { + notify(player, T("I can't see that here.")); + return 0; + } + if (!flag || !*flag) { + notify(player, T("What do you want to set?")); + return 0; + } + + name = mush_strdup(xname, "ds.string"); + /* check for attribute flag set first */ if ((p = strchr(name, '/')) != NULL) { *p++ = '\0'; do_attrib_flags(player, name, p, flag); + mush_free(name, "ds.string"); return 1; } + /* find thing */ - if(!GoodObject((thing = match_thing(player, name)))) - return 0; - if (God(thing) && !God(player)) { + if ((thing = match_controlled(player, name)) == NOTHING) { + mush_free(name, "ds.string"); + return 0; + } + + mush_free(name, "ds.string"); + + if (God(thing) && !God(player)) { notify(player, T("Only God can set himself!")); return 0; } + + /* check for attribute set first */ if ((p = strchr(flag, ':')) != NULL) { *p++ = '\0'; @@ -588,7 +589,7 @@ do_set(dbref player, const char *name, char *flag) return do_set_atr(thing, flag, p, player, 1); } /* we haven't set an attribute, so we must be setting flags */ - strcpy(flagbuff, flag); + mush_strncpy(flagbuff, flag, BUFFER_LEN); p = trim_space_sep(flagbuff, ' '); if (*p == '\0') { notify(player, T("You must specify a flag to set.")); @@ -692,12 +693,12 @@ do_cpattr(dbref player, char *oldpair, char **newpair, int move, int noflagcopy) free((Malloc_t) text); /* safe_uncompress malloc()s memory */ if (copies) { notify_format(player, T("Attribute %s (%d copies)"), - (move ? "moved" : "copied"), copies); + (move ? T("moved") : T("copied")), copies); if (move) do_set_atr(oldobj, AL_NAME(a), NULL, player, 1); } else { notify_format(player, T("Unable to %s attribute."), - (move ? "move" : "copy")); + (move ? T("move") : T("copy"))); } return; } @@ -750,14 +751,14 @@ gedit_helper(dbref player, dbref thing, safe_str(r, tbuf1, &tbufp); if (safe_format(tbuf_ansi, &tbufap, "%s%s%s%s", s, ANSI_HILITE, r, - ANSI_NORMAL)) + ANSI_END)) ansi_long_flag = 1; } else if (vlen == 1 && *val == '^') { /* prepend */ safe_str(r, tbuf1, &tbufp); safe_str(s, tbuf1, &tbufp); - if (safe_format(tbuf_ansi, &tbufap, "%s%s%s%s", ANSI_HILITE, r, ANSI_NORMAL, + if (safe_format(tbuf_ansi, &tbufap, "%s%s%s%s", ANSI_HILITE, r, ANSI_END, s)) ansi_long_flag = 1; } else if (!*val) { @@ -771,7 +772,7 @@ gedit_helper(dbref player, dbref thing, /* Add one at the start */ if (!safe_strl(r, rlen, tbuf1, &tbufp)) { if (gargs->target != EDIT_FIRST) { - for (last = 0; last < haystack->len; last++) { + for (last = 0; last < (size_t) haystack->len; last++) { /* Add the next character */ if (safe_ansi_string(haystack, last, 1, tbuf1, &tbufp)) { too_long = 1; @@ -782,13 +783,13 @@ gedit_helper(dbref player, dbref thing, ansi_long_flag = 1; } /* Copy in r */ - if (safe_strl(r, rlen, tbuf1, &tbufp)) { + if (safe_str(r, tbuf1, &tbufp)) { too_long = 1; break; } if (!ansi_long_flag) { if (safe_format(tbuf_ansi, &tbufap, "%s%s%s", ANSI_HILITE, r, - ANSI_NORMAL)) + ANSI_END)) ansi_long_flag = 1; } } @@ -804,7 +805,7 @@ gedit_helper(dbref player, dbref thing, haystack = parse_ansi_string(s); - while (last < haystack->len + while (last < (size_t) haystack->len && (p = strstr(haystack->text + last, val)) != NULL) { if (safe_ansi_string(haystack, last, p - (haystack->text + last), tbuf1, &tbufp)) { @@ -818,20 +819,19 @@ gedit_helper(dbref player, dbref thing, } /* Copy in r */ - if (safe_strl(r, rlen, tbuf1, &tbufp)) { + if (safe_str(r, tbuf1, &tbufp)) { too_long = 1; break; } if (!ansi_long_flag) { - if (safe_format(tbuf_ansi, &tbufap, "%s%s%s", ANSI_HILITE, r, - ANSI_NORMAL)) + if (safe_format(tbuf_ansi, &tbufap, "%s%s%s", ANSI_HILITE, r, ANSI_END)) ansi_long_flag = 1; } last = p - haystack->text + vlen; if (gargs->target == EDIT_FIRST) break; } - if (last < haystack->len && !too_long) { + if (last < (size_t) haystack->len && !too_long) { safe_ansi_string(haystack, last, haystack->len, tbuf1, &tbufp); if (!ansi_long_flag) { if (safe_ansi_string(haystack, last, haystack->len, tbuf_ansi, &tbufap)) @@ -848,9 +848,9 @@ gedit_helper(dbref player, dbref thing, if (do_set_atr(thing, AL_NAME(a), tbuf1, player, 0) && !AreQuiet(player, thing)) { if (!ansi_long_flag && ShowAnsi(player)) - notify_format(player, "%s - Set: %s", AL_NAME(a), tbuf_ansi); + notify_format(player, T("%s - Set: %s"), AL_NAME(a), tbuf_ansi); else - notify_format(player, "%s - Set: %s", AL_NAME(a), tbuf1); + notify_format(player, T("%s - Set: %s"), AL_NAME(a), tbuf1); } } else { /* We don't do it - we just pemit it. */ @@ -987,7 +987,7 @@ do_use(dbref player, const char *what) fail_lock(player, thing, Use_Lock, T("Permission denied."), NOTHING); return; } else - did_it(player, thing, "USE", "Used.", "OUSE", NULL, "AUSE", NOTHING); + did_it(player, thing, "USE", T("Used."), "OUSE", NULL, "AUSE", NOTHING); } } @@ -1139,7 +1139,8 @@ do_wipe(dbref player, char *name) return; } - switch ((wiped = atr_iter_get(player, thing, pattern, 0, wipe_helper, NULL))) { + wiped = atr_iter_get(player, thing, pattern, 0, wipe_helper, NULL); + switch (wiped) { case 0: notify(player, T("No attributes wiped.")); break; diff --git a/src/shs.c b/src/shs.c index 34223d5..fe078ea 100644 --- a/src/shs.c +++ b/src/shs.c @@ -316,9 +316,9 @@ shsTransform(SHS_INFO *shsInfo) } /* end of shsTransform */ -static void byteReverse(LONG * buffer, int byteCount); +static void byteReverse(LONG *buffer, int byteCount); static void -byteReverse(LONG * buffer, int byteCount) +byteReverse(LONG *buffer, int byteCount) { LONG value; int count; @@ -341,7 +341,7 @@ byteReverse(LONG * buffer, int byteCount) * \param count size of buffer in bytes. */ void -shsUpdate(SHS_INFO *shsInfo, const BYTE * buffer, int count) +shsUpdate(SHS_INFO *shsInfo, const BYTE *buffer, int count) { /* Update bitcount */ diff --git a/src/sig.c b/src/sig.c index 8558619..dccfc66 100644 --- a/src/sig.c +++ b/src/sig.c @@ -12,7 +12,7 @@ #include "externs.h" #include "confmagic.h" -#ifndef HAS_SIGPROCMASK +#ifndef HAVE_SIGPROCMASK static Sigfunc saved_handlers[NSIG]; #endif @@ -31,7 +31,7 @@ static Sigfunc saved_handlers[NSIG]; Sigfunc install_sig_handler(int signo, Sigfunc func) { -#ifdef HAS_SIGACTION +#ifdef HAVE_SIGACTION struct sigaction act, oact; act.sa_handler = func; sigemptyset(&act.sa_mask); @@ -55,7 +55,7 @@ void reload_sig_handler(int signo __attribute__ ((__unused__)), Sigfunc func __attribute__ ((__unused__))) { -#if !(defined(HAS_SIGACTION) || defined(SIGNALS_KEPT)) +#if !(defined(HAVE_SIGACTION) || defined(SIGNALS_KEPT)) signal(signo, func); #endif } @@ -66,7 +66,7 @@ reload_sig_handler(int signo __attribute__ ((__unused__)), void ignore_signal(int signo) { -#ifdef HAS_SIGACTION +#ifdef HAVE_SIGACTION struct sigaction act; act.sa_handler = SIG_IGN; sigemptyset(&act.sa_mask); @@ -84,7 +84,7 @@ ignore_signal(int signo) void block_a_signal(int signo) { -#ifdef HAS_SIGPROCMASK +#ifdef HAVE_SIGPROCMASK sigset_t mask; sigemptyset(&mask); sigaddset(&mask, signo); @@ -102,7 +102,7 @@ block_a_signal(int signo) void unblock_a_signal(int signo) { -#ifdef HAS_SIGPROCMASK +#ifdef HAVE_SIGPROCMASK sigset_t mask; if (signo >= 0 && signo < NSIG) { sigemptyset(&mask); @@ -120,21 +120,21 @@ unblock_a_signal(int signo) void block_signals(void) { -#ifdef HAS_SIGPROCMASK +#ifdef HAVE_SIGPROCMASK sigset_t mask; sigfillset(&mask); sigprocmask(SIG_BLOCK, &mask, NULL); #elif defined(WIN32) - /* The only signals Windows knows about */ - signal(SIGABRT, SIG_IGN); - signal(SIGFPE, SIG_IGN); - signal(SIGILL, SIG_IGN); - signal(SIGINT, SIG_IGN); - signal(SIGSEGV, SIG_IGN); - signal(SIGTERM, SIG_IGN); + /* The only signals Windows knows about. Can these even /be/ ignored? */ + saved_handlers[SIGABRT] = signal(SIGABRT, SIG_IGN); + saved_handlers[SIGFPE] = signal(SIGFPE, SIG_IGN); + saved_handlers[SIGILL] = signal(SIGILL, SIG_IGN); + saved_handlers[SIGINT] = signal(SIGINT, SIG_IGN); + saved_handlers[SIGSEGV] = signal(SIGSEGV, SIG_IGN); + saved_handlers[SIGTERM] = signal(SIGTERM, SIG_IGN); #else int i; for (i = 0; i < NSIG; i++) - signal(i, SIG_IGN); + saved_handlers[i] = signal(i, SIG_IGN); #endif } diff --git a/src/sort.c b/src/sort.c new file mode 100644 index 0000000..ffca23f --- /dev/null +++ b/src/sort.c @@ -0,0 +1,711 @@ +/** + * \file sort.c + * \brief Sorting and comparision functions + */ +#include "copyrite.h" + +#include "config.h" +#include +#include +#include "conf.h" +#include "externs.h" +#include "lock.h" +#include "parse.h" +#include "ansi.h" +#include "command.h" +#include "sort.h" +#include "confmagic.h" + + +#define EPSILON 0.000000001 /**< limit of precision for float equality */ + +/** qsort() comparision routine for int */ +int +int_comp(const void *s1, const void *s2) +{ + int a, b; + + a = *(const int *) s1; + b = *(const int *) s2; + + if (a == b) + return 0; + else if (a < b) + return -1; + else + return 1; +} + + +/** qsort() comparision routine for unsigned int */ +int +uint_comp(const void *s1, const void *s2) +{ + unsigned int a, b; + + a = *(const unsigned int *) s1; + b = *(const unsigned int *) s2; + + if (a == b) + return 0; + else if (a < b) + return -1; + else + return 1; +} + + +/** qsort() comparision routine for NVAL/double */ +int +nval_comp(const void *a, const void *b) +{ + const NVAL *x = a, *y = b; + const double epsilon = pow(10.0, -FLOAT_PRECISION); + int eq = (fabs(*x - *y) <= (epsilon * fabs(*x))); + return eq ? 0 : (*x > *y ? 1 : -1); +} + + +/** qsort() comparision routine for strings. + * Uses strcmp() + */ +int +str_comp(const void *s1, const void *s2) +{ + const char *a, *b; + + a = *(const char **) s1; + b = *(const char **) s2; + + return strcmp(a, b); +} + +/** qsort() comparision routine for strings. + * Uses strcasecmp(). + * Case-insensitive. + */ +int +stri_comp(const void *s1, const void *s2) +{ + const char *a, *b; + + a = *(const char **) s1; + b = *(const char **) s2; + + return strcasecmp(a, b); +} + +/** qsort() comparision routine for dbrefs. */ +int +dbref_comp(const void *s1, const void *s2) +{ + dbref a, b; + + a = *(const dbref *) s1; + b = *(const dbref *) s2; + + if (a == b) + return 0; + else if (a < b) + return -1; + else + return 1; +} + + +dbref ucomp_executor, ucomp_caller, ucomp_enactor; +char ucomp_buff[BUFFER_LEN]; +PE_Info *ucomp_pe_info; + +/** qsort() comparision routine used by sortby() */ +int +u_comp(const void *s1, const void *s2) +{ + char result[BUFFER_LEN], *rp; + char const *tbuf; + int n; + + /* Our two arguments are passed as %0 and %1 to the sortby u-function. */ + + /* Note that this function is for use in conjunction with our own + * sane_qsort routine, NOT with the standard library qsort! + */ + global_eval_context.wenv[0] = (char *) s1; + global_eval_context.wenv[1] = (char *) s2; + + /* Run the u-function, which should return a number. */ + + tbuf = ucomp_buff; + rp = result; + if (process_expression(result, &rp, &tbuf, + ucomp_executor, ucomp_caller, ucomp_enactor, + PE_DEFAULT, PT_DEFAULT, ucomp_pe_info)) + return 0; + n = parse_integer(result); + + return n; +} + + + +/** Used with fun_sortby() + * + * Based on Andrew Molitor's qsort, which doesn't require transitivity + * between comparisons (essential for preventing crashes due to + * boneheads who write comparison functions where a > b doesn't mean b + * < a). + * + * Actually, this sort doesn't require commutivity. + * Sorting doesn't make sense without transitivity... + */ + +void +sane_qsort(void *array[], int left, int right, comp_func compare) +{ + + int i, last; + void *tmp; + +loop: + if (left >= right) + return; + + /* Pick something at random at swap it into the leftmost slot */ + /* This is the pivot, we'll put it back in the right spot later */ + + i = get_random_long(left, right); + tmp = array[i]; + array[i] = array[left]; + array[left] = tmp; + + last = left; + for (i = left + 1; i <= right; i++) { + + /* Walk the array, looking for stuff that's less than our */ + /* pivot. If it is, swap it with the next thing along */ + + if (compare(array[i], array[left]) < 0) { + last++; + if (last == i) + continue; + + tmp = array[last]; + array[last] = array[i]; + array[i] = tmp; + } + } + + /* Now we put the pivot back, it's now in the right spot, we never */ + /* need to look at it again, trust me. */ + + tmp = array[last]; + array[last] = array[left]; + array[left] = tmp; + + /* At this point everything underneath the 'last' index is < the */ + /* entry at 'last' and everything above it is not < it. */ + + if ((last - left) < (right - last)) { + sane_qsort(array, left, last - 1, compare); + left = last + 1; + goto loop; + } else { + sane_qsort(array, last + 1, right, compare); + right = last - 1; + goto loop; + } +} + + + + +/****************************** gensort ************/ + +typedef struct sort_record s_rec; + +/** Sorting strings by different values. We store both the string and + * its 'key' to sort by. Sort of a hardcode munge. + */ +struct sort_record { + char *ptr; /**< NULL except for sortkey */ + char *val; /**< The string this is */ + dbref db; /**< dbref (default 0, bad is -1) */ + union { + struct { + char *s; /**< string comparisons */ + bool freestr; /**< free str on completion */ + } str; + int num; /**< integer comparisons */ + NVAL numval; /**< float comparisons */ + time_t tm; /**< time comparisions */ + } memo; +}; + + +#define GENRECORD(x) void x(s_rec *rec,dbref player,char *sortflags); \ + void x(s_rec *rec, \ + dbref player __attribute__ ((__unused__)), \ + char *sortflags __attribute__ ((__unused__))) + + + +GENRECORD(gen_alphanum) +{ + size_t len; + if (strchr(rec->val, ESC_CHAR) || strchr(rec->val, TAG_START)) { + rec->memo.str.s = mush_strdup(remove_markup(rec->val, &len), "genrecord"); + rec->memo.str.freestr = 1; + } else { + rec->memo.str.s = rec->val; + rec->memo.str.freestr = 0; + } +} + +GENRECORD(gen_dbref) +{ + rec->memo.num = qparse_dbref(rec->val); +} + +GENRECORD(gen_num) +{ + rec->memo.num = parse_integer(rec->val); +} + +GENRECORD(gen_float) +{ + rec->memo.numval = parse_number(rec->val); +} + +#define RealGoodObject(x) (GoodObject(x) && !IsGarbage(x)) + +GENRECORD(gen_db_name) +{ + rec->memo.str.s = (char *) ""; + if (RealGoodObject(rec->db)) + rec->memo.str.s = (char *) Name(rec->db); + rec->memo.str.freestr = 0; +} + +GENRECORD(gen_db_idle) +{ + rec->memo.num = -1; + if (RealGoodObject(rec->db)) { + if (Priv_Who(player)) + rec->memo.num = least_idle_time_priv(rec->db); + else + rec->memo.num = least_idle_time(rec->db); + } +} + +GENRECORD(gen_db_conn) +{ + rec->memo.num = -1; + if (RealGoodObject(rec->db)) { + if (Priv_Who(player)) + rec->memo.num = most_conn_time_priv(rec->db); + else + rec->memo.num = most_conn_time(rec->db); + } +} + +GENRECORD(gen_db_ctime) +{ + if (RealGoodObject(rec->db)) + rec->memo.tm = CreTime(rec->db); +} + +GENRECORD(gen_db_owner) +{ + if (RealGoodObject(rec->db)) + rec->memo.num = Owner(rec->db); +} + +GENRECORD(gen_db_loc) +{ + rec->memo.num = -1; + if (RealGoodObject(rec->db) && Can_Locate(player, rec->db)) { + rec->memo.num = Location(rec->db); + } +} + +GENRECORD(gen_db_attr) +{ + /* Eek, I hate dealing with memory issues. */ + + static char *defstr = (char *) ""; + const char *ptr; + + rec->memo.str.s = defstr; + rec->memo.str.freestr = 0; + if (RealGoodObject(rec->db) && sortflags && *sortflags && + (ptr = do_get_attrib(player, rec->db, sortflags)) != NULL) { + rec->memo.str.s = mush_strdup(ptr, "genrecord"); + rec->memo.str.freestr = 1; + } +} + + +typedef int (*qsort_func) (const void *, const void *); +typedef void (*makerecord) (s_rec *, dbref player, char *sortflags); + + +/* Compare(r,x,y) { + * if (x->db < 0 && y->db < 0) + * return 0; // Garbage is identical. + * if (x->db < 0) + * return 2; // Garbage goes last. + * if (y->db < 0) + * return -2; // Garbage goes last. + * if (r < 0) + * return -2; // different + * if (r > 0) + * return 2; // different + * if (x->db < y->db) + * return -1; // similar + * if (y->db < x-db) + * return 1; // similar + * return 0; // identical + * } + */ + +/* If I could, I'd let sort() toss out non-existant dbrefs + * Instead, sort stuffs them into a jumble at the end. */ + +/* Compare a single int, > == or < 0 */ +#define Compare(i,x,y) \ + ((x->db < 0 || y->db < 0) ? \ + ((x->db < 0 && y->db < 0) ? 0 : (x->db < 0 ? 2 : -2)) \ + : ((i != 0) ? (i < 0 ? -2 : 2) \ + : (x->db == y->db ? 0 : (x->db < y->db ? -1 : 1)) \ + ) \ + ) + +/* Compare a float, > == or < 0.0 */ +#define CompareF(f,x,y) \ + ((x->db < 0 || y->db < 0) ? \ + ((x->db < 0 && y->db < 0) ? 0 : (x->db < 0 ? 2 : -2)) \ + : ((fabs(f) > EPSILON) ? (f < 0.0 ? -2 : 2) \ + : (x->db == y->db ? 0 : (x->db < y->db ? -1 : 1)) \ + ) \ + ) + +/* Compare two ints */ +#define Compare2(i1,i2,x,y) \ + ((x->db < 0 || y->db < 0) ? \ + ((x->db < 0 && y->db < 0) ? 0 : (x->db < 0 ? 2 : -2)) \ + : ((i1 != i2) ? (i1 < i2 ? -2 : 2) \ + : (x->db == y->db ? 0 : (x->db < y->db ? -1 : 1)) \ + ) \ + ) + +/* Compare two doubles */ +#define Compare2F(f1,f2,x,y) \ + ((x->db < 0 || y->db < 0) ? \ + ((x->db < 0 && y->db < 0) ? 0 : (x->db < 0 ? 2 : -2)) \ + : ((fabs(f1 - f2) > EPSILON) ? (f1 < f2 ? -2 : 2) \ + : (x->db == y->db ? 0 : (x->db < y->db ? -1 : 1)) \ + ) \ + ) + +static int +s_comp(const void *s1, const void *s2) +{ + const s_rec *sr1 = (const s_rec *) s1; + const s_rec *sr2 = (const s_rec *) s2; + int res = 0; + res = strcoll(sr1->memo.str.s, sr2->memo.str.s); + return Compare(res, sr1, sr2); +} + +static int +si_comp(const void *s1, const void *s2) +{ + const s_rec *sr1 = (const s_rec *) s1; + const s_rec *sr2 = (const s_rec *) s2; + int res = 0; + res = strcasecoll(sr1->memo.str.s, sr2->memo.str.s); + return Compare(res, sr1, sr2); +} + +static int +i_comp(const void *s1, const void *s2) +{ + const s_rec *sr1 = (const s_rec *) s1; + const s_rec *sr2 = (const s_rec *) s2; + return Compare2(sr1->memo.num, sr2->memo.num, sr1, sr2); +} + +static int +tm_comp(const void *s1, const void *s2) +{ + const s_rec *sr1 = (const s_rec *) s1; + const s_rec *sr2 = (const s_rec *) s2; + double r = difftime(sr1->memo.tm, sr2->memo.tm); + return CompareF(r, sr1, sr2); +} + +static int +f_comp(const void *s1, const void *s2) +{ + const s_rec *sr1 = (const s_rec *) s1; + const s_rec *sr2 = (const s_rec *) s2; + return Compare2F(sr1->memo.numval, sr2->memo.numval, sr1, sr2); +} + +typedef struct _list_type_list_ { + char *name; + makerecord make_record; + qsort_func sorter; + uint32_t flags; +} list_type_list; + +#define IS_DB 0x1U +#define IS_STRING 0x2U + +char ALPHANUM_LIST[] = "A"; +char INSENS_ALPHANUM_LIST[] = "I"; +char DBREF_LIST[] = "D"; +char NUMERIC_LIST[] = "N"; +char FLOAT_LIST[] = "F"; +char DBREF_NAME_LIST[] = "NAME"; +char DBREF_NAMEI_LIST[] = "NAMEI"; +char DBREF_IDLE_LIST[] = "IDLE"; +char DBREF_CONN_LIST[] = "CONN"; +char DBREF_CTIME_LIST[] = "CTIME"; +char DBREF_OWNER_LIST[] = "OWNER"; +char DBREF_LOCATION_LIST[] = "LOC"; +char DBREF_ATTR_LIST[] = "ATTR"; +char DBREF_ATTRI_LIST[] = "ATTRI"; +char *UNKNOWN_LIST = NULL; + +list_type_list ltypelist[] = { + /* List type name, recordmaker, comparer, dbrefs? */ + {ALPHANUM_LIST, gen_alphanum, s_comp, IS_STRING}, + {INSENS_ALPHANUM_LIST, gen_alphanum, si_comp, IS_STRING}, + {DBREF_LIST, gen_dbref, i_comp, 0}, + {NUMERIC_LIST, gen_num, i_comp, 0}, + {FLOAT_LIST, gen_float, f_comp, 0}, + {DBREF_NAME_LIST, gen_db_name, si_comp, IS_DB | IS_STRING}, + {DBREF_NAMEI_LIST, gen_db_name, si_comp, IS_DB | IS_STRING}, + {DBREF_IDLE_LIST, gen_db_idle, i_comp, IS_DB}, + {DBREF_CONN_LIST, gen_db_conn, i_comp, IS_DB}, + {DBREF_CTIME_LIST, gen_db_ctime, tm_comp, IS_DB}, + {DBREF_OWNER_LIST, gen_db_owner, i_comp, IS_DB}, + {DBREF_LOCATION_LIST, gen_db_loc, i_comp, IS_DB}, + {DBREF_ATTR_LIST, gen_db_attr, s_comp, IS_DB | IS_STRING}, + {DBREF_ATTRI_LIST, gen_db_attr, si_comp, IS_DB | IS_STRING}, + /* This stops the loop, so is default */ + {NULL, gen_alphanum, s_comp, IS_STRING} +}; + +char * +get_list_type(char *args[], int nargs, int type_pos, char *ptrs[], int nptrs) +{ + static char stype[BUFFER_LEN]; + int i; + char *str; + if (nargs >= type_pos) { + str = args[type_pos - 1]; + if (*str) { + strcpy(stype, str); + str = strchr(stype, ':'); + if (str) + *(str++) = '\0'; + for (i = 0; ltypelist[i].name && strcasecmp(ltypelist[i].name, stype); + i++) ; + /* return ltypelist[i].name; */ + if (ltypelist[i].name) { + return args[type_pos - 1]; + } + } + } + return autodetect_list(ptrs, nptrs); +} + +char * +get_list_type_noauto(char *args[], int nargs, int type_pos) +{ + static char stype[BUFFER_LEN]; + int i; + char *str; + if (nargs >= type_pos) { + str = args[type_pos - 1]; + if (*str) { + strcpy(stype, str); + str = strchr(stype, ':'); + if (str) + *(str++) = '\0'; + for (i = 0; ltypelist[i].name && strcasecmp(ltypelist[i].name, stype); + i++) ; + /* return ltypelist[i].name; */ + return args[type_pos - 1]; + } + } + return UNKNOWN_LIST; +} + + +/** A generic comparer routine to compare two values of any sort type. + * \param + */ +int +gencomp(dbref player, char *a, char *b, char *sort_type) +{ + char *ptr; + int i, len; + int result; + s_rec s1, s2; + ptr = NULL; + if (!sort_type) { + /* Advance i to the default */ + for (i = 0; ltypelist[i].name; i++) ; + } else if ((ptr = strchr(sort_type, ':'))) { + len = ptr - sort_type; + ptr += 1; + if (!*ptr) + ptr = NULL; + for (i = 0; + ltypelist[i].name && strncasecmp(ltypelist[i].name, sort_type, len); + i++) ; + } else { + for (i = 0; ltypelist[i].name && strcasecmp(ltypelist[i].name, sort_type); + i++) ; + } + if (ltypelist[i].flags & IS_DB) { + s1.db = parse_objid(a); + s2.db = parse_objid(b); + if (!RealGoodObject(s1.db)) + s1.db = NOTHING; + if (!RealGoodObject(s2.db)) + s2.db = NOTHING; + } else { + s1.db = s2.db = 0; + } + + s1.val = a; + s2.val = b; + ltypelist[i].make_record(&s1, player, ptr); + ltypelist[i].make_record(&s2, player, ptr); + result = ltypelist[i].sorter((const void *) &s1, (const void *) &s2); + if (ltypelist[i].flags & IS_STRING) { + if (s1.memo.str.freestr) + mush_free(s1.memo.str.s, "genrecord"); + if (s2.memo.str.freestr) + mush_free(s2.memo.str.s, "genrecord"); + } + return result; +} + +/** A generic sort routine to sort several different + * types of arrays, in place. + * \param player the player executing the sort. + * \param s the array to sort. + * \param n number of elements in array s + * \param sort_type the string that describes the sort type. + */ + +void +do_gensort(dbref player, char *keys[], char *strs[], int n, char *sort_type) +{ + char *ptr; + static char stype[BUFFER_LEN]; + int i, sorti; + s_rec *sp; + ptr = NULL; + if (!sort_type || !*sort_type) { + /* Advance sorti to the default */ + for (sorti = 0; ltypelist[sorti].name; sorti++) ; + } else if (strchr(sort_type, ':') != NULL) { + strcpy(stype, sort_type); + ptr = strchr(stype, ':'); + *(ptr++) = '\0'; + if (!*ptr) + ptr = NULL; + for (sorti = 0; + ltypelist[sorti].name && strcasecmp(ltypelist[sorti].name, stype); + sorti++) ; + } else { + for (sorti = 0; + ltypelist[sorti].name && strcasecmp(ltypelist[sorti].name, sort_type); + sorti++) ; + } + sp = mush_calloc(n, sizeof(s_rec), "do_gensort"); + for (i = 0; i < n; i++) { + /* Elements are 0 by default thanks to calloc. Only need to touch + those that need other values. */ + sp[i].val = keys[i]; + if (strs) + sp[i].ptr = strs[i]; + if (ltypelist[sorti].flags & IS_DB) { + sp[i].db = parse_objid(keys[i]); + if (!RealGoodObject(sp[i].db)) + sp[i].db = NOTHING; + } + ltypelist[sorti].make_record(&(sp[i]), player, ptr); + } + qsort((void *) sp, n, sizeof(s_rec), ltypelist[sorti].sorter); + + for (i = 0; i < n; i++) { + keys[i] = sp[i].val; + if (strs) { + strs[i] = sp[i].ptr; + } + if ((ltypelist[sorti].flags & IS_STRING) && sp[i].memo.str.freestr) + mush_free(sp[i].memo.str.s, "genrecord"); + } + mush_free(sp, "do_gensort"); +} + +typedef enum { + L_NUMERIC, + L_FLOAT, + L_ALPHANUM, + L_DBREF +} ltype; + +char * +autodetect_list(char *ptrs[], int nptrs) +{ + char *sort_type; + ltype lt; + int i; + + lt = L_NUMERIC; + sort_type = NUMERIC_LIST; + + for (i = 0; i < nptrs; i++) { + switch (lt) { + case L_NUMERIC: + if (!is_strict_integer(ptrs[i])) { + /* If it's not an integer, see if it's a floating-point number */ + if (is_strict_number(ptrs[i])) { + lt = L_FLOAT; + sort_type = FLOAT_LIST; + } else if (i == 0) { + + /* If we get something non-numeric, switch to an + * alphanumeric guess, unless this is the first + * element and we have a dbref. + */ + if (is_objid(ptrs[i])) { + lt = L_DBREF; + sort_type = DBREF_LIST; + } else + return ALPHANUM_LIST; + } + } + break; + case L_FLOAT: + if (!is_strict_number(ptrs[i])) + return ALPHANUM_LIST; + break; + case L_DBREF: + if (!is_objid(ptrs[i])) + return ALPHANUM_LIST; + break; + default: + return ALPHANUM_LIST; + } + } + return sort_type; +} diff --git a/src/speech.c b/src/speech.c index 1aaee3c..8bad6b0 100644 --- a/src/speech.c +++ b/src/speech.c @@ -12,9 +12,10 @@ #include #include #include +#include #include "conf.h" -#include "ansi.h" #include "externs.h" +#include "ansi.h" #include "mushdb.h" #include "dbdefs.h" #include "lock.h" @@ -24,7 +25,8 @@ #include "attrib.h" #include "parse.h" #include "game.h" -#include "pcre.h" +#include "mypcre.h" +#include "sort.h" #include "confmagic.h" int okay_pemit(dbref player, dbref target); @@ -34,8 +36,6 @@ static void do_audible_stuff(dbref loc, dbref *excs, int numexcs, const char *msg); static void do_one_remit(dbref player, const char *target, const char *msg, int flags); -static int dbref_comp(const void *a, const void *b); - dbref na_zemit(dbref current, void *data); const char * @@ -132,7 +132,7 @@ do_teach(dbref player, dbref cause, const char *tbuf1) recurse = 1; /* Protect use from recursive teach */ notify_except(Contents(loc), NOTHING, tprintf(T("%s types --> %s%s%s"), spname(player), - ANSI_HILITE, tbuf1, ANSI_NORMAL), NA_INTER_HEAR); + ANSI_HILITE, tbuf1, ANSI_END), NA_INTER_HEAR); command = mush_strdup(tbuf1, "string"); /* process_command is destructive */ process_command(player, command, cause, cause, 1); mush_free(command, "string"); @@ -167,19 +167,6 @@ do_say(dbref player, const char *tbuf1) NA_INTER_HEAR); } -/** A comparator for raw dbrefs. - * This exists because the i_comp function in funlist.c got hairy some time ago. - * \param a the first element to compare. - * \param b the second element to compare. - */ -static int -dbref_comp(const void *a, const void *b) -{ - const dbref *x = (const dbref *) a; - const dbref *y = (const dbref *) b; - return (int) *x - (int) *y; -} - /** The oemit(/list) command. * \verbatim * This implements @oemit and @oemit/list. @@ -358,7 +345,7 @@ do_whisper(dbref player, const char *arg1, const char *arg2, int noisy) notify_format(player, T("Unable to whisper to:%s"), tbuf); if (!gcount) { - mush_free((Malloc_t) tbuf, "string"); + mush_free(tbuf, "string"); return; } @@ -368,7 +355,7 @@ do_whisper(dbref player, const char *arg1, const char *arg2, int noisy) /* Set up list of good names */ tp = tbuf; - safe_str(" to ", tbuf, &tp); + safe_str(T(" to "), tbuf, &tp); for (who = 0; who < gcount; who++) { if (noisy && (get_random_long(0, 100) < WHISPER_LOUDNESS)) overheard = 1; @@ -383,7 +370,7 @@ do_whisper(dbref player, const char *arg1, const char *arg2, int noisy) p = tprintf("You sense: %s%s%s", Name(player), gap, arg2); } else { notify_format(player, T("You whisper, \"%s\"%s."), arg2, tbuf); - p = tprintf("%s whispers%s: %s", Name(player), + p = tprintf(T("%s whispers%s: %s"), Name(player), gcount > 1 ? tbuf : "", arg2); } @@ -396,7 +383,7 @@ do_whisper(dbref player, const char *arg1, const char *arg2, int noisy) dbref first = Contents(Location(player)); if (!GoodObject(first)) return; - p = tprintf("%s whispers%s.", Name(player), tbuf); + p = tprintf(T("%s whispers%s."), Name(player), tbuf); DOLIST(first, first) { overheard = 1; for (who = 0; who < gcount; who++) { @@ -409,7 +396,64 @@ do_whisper(dbref player, const char *arg1, const char *arg2, int noisy) notify_noecho(first, p); } } - mush_free((Malloc_t) tbuf, "string"); + mush_free(tbuf, "string"); +} + +/** Send an @message to a list of dbrefs, using to format it + * if present. + * The list is destructively modified. + * \param player the enactor. + * \param list the list of players to pemit to, destructively modified. + * \param attrib the ufun attribute to use to format the message. + * \param message the default message. + * \param flags PEMIT_* flags + * \param numargs The number of arguments for the ufun. + * \param ... The arguments for the ufun. + */ +void +do_message_list(dbref player, dbref enactor, char *list, char *attrname, + char *message, int flags, int numargs, char *argv[]) +{ + const char *start; + char *current; + char plist[BUFFER_LEN], *pp; + dbref victim; + int first = 0; + ATTR *attrib; + + start = list; + + pp = plist; + *pp = '\0'; + + while (start && *start) { + current = next_in_list(&start); + if (*current == '*') + current = current + 1; + victim = noisy_match_result(player, current, NOTYPE, MAT_EVERYTHING); + if (GoodObject(victim) && !IsGarbage(victim)) { + /* Can we evaluate its ? */ + + attrib = atr_get(victim, upcasestr(attrname)); + if (attrib && CanEvalAttr(player, victim, attrib)) { + if (flags & PEMIT_SPOOF) { + messageformat(victim, attrname, enactor, NA_SPOOF, numargs, argv); + } else { + messageformat(victim, attrname, enactor, 0, numargs, argv); + } + } else { + if (!first) { + safe_chr(' ', plist, &pp); + } + first = 0; + safe_dbref(victim, plist, &pp); + } + } + } + if (plist[0]) { + *pp = '\0'; + do_pemit_list(enactor, plist, message, flags); + } } /** Send a message to a list of dbrefs. To avoid repeated generation @@ -604,7 +648,76 @@ do_wall(dbref player, const char *message, enum wall_type target, int emit) else flag_broadcast(mask, 0, "%s %s %s, \"%s\"", prefix, Name(player), - target == WALL_ALL ? "shouts" : "says", message); + target == WALL_ALL ? T("shouts") : T("says"), message); +} + +/** messageformat. This is the wrapper that makes calling PAGEFORMAT, + * CHATFORMAT, etc easy. + * + * \param player The victim to call it on. + * \param attribute The attribute on the player to call. + * \param enactor The enactor who caused the message. + * \param flags NA_INTER_HEAR and NA_SPOOF + * \param arg0 First argument + * \param arg4 Last argument. + * \retval 1 The player had the fooformat attribute. + * \retval 0 The default message was sent. + */ +int +vmessageformat(dbref player, const char *attribute, dbref enactor, int flags, + int numargs, ...) +{ + va_list ap; + char *s; + int i; + char *argv[10]; + + va_start(ap, numargs); + + for (i = 0; i < 10; i++) { + if (i < numargs) { + /* Pop another char * off the stack. */ + s = va_arg(ap, char *); + argv[i] = s; + } else { + argv[i] = NULL; + } + } + va_end(ap); + + return messageformat(player, attribute, enactor, flags, numargs, argv); +} + +/** messageformat. This is the wrapper that makes calling PAGEFORMAT, + * CHATFORMAT, etc easy. + * + * \param player The victim to call it on. + * \param attribute The attribute on the player to call. + * \param enactor The enactor who caused the message. + * \param flags NA_INTER_HEAR and NA_SPOOF + * \param arg0 First argument + * \param arg4 Last argument. + * \retval 1 The player had the fooformat attribute. + * \retval 0 The default message was sent. + */ +int +messageformat(dbref player, const char *attribute, dbref enactor, int flags, + int numargs, char *argv[]) +{ + /* It's only static because I expect this thing to get + * called a LOT, so it may or may not save time. */ + static char messbuff[BUFFER_LEN]; + + *messbuff = '\0'; + if (!call_attrib(player, attribute, (const char **) argv, numargs, + messbuff, enactor, NULL)) { + /* We have a returned value. Notify the player. */ + if (*messbuff) + notify_anything(enactor, na_one, &player, ns_esnotify, flags, messbuff); + return 1; + } else { + return 0; + } } /** The page command. @@ -641,7 +754,7 @@ do_page(dbref player, const char *arg1, const char *arg2, dbref cause, ATTR *a; char *alias; - tp2 = tbuf2 = (char *) mush_malloc(BUFFER_LEN, "string"); + tp2 = tbuf2 = (char *) mush_malloc(BUFFER_LEN, "page_buff"); if (!tbuf2) mush_panic("Unable to allocate memory in do_page"); @@ -665,19 +778,19 @@ do_page(dbref player, const char *arg1, const char *arg2, dbref cause, a = atr_get_noparent(player, "LASTPAGED"); if (!a || !*((hp = head = safe_atr_value(a)))) { notify(player, T("You haven't paged anyone since connecting.")); - mush_free((Malloc_t) tbuf2, "string"); + mush_free((Malloc_t) tbuf2, "page_buff"); return; } if (!message || !*message) { notify_format(player, T("You last paged %s."), head); - mush_free((Malloc_t) tbuf2, "string"); + mush_free((Malloc_t) tbuf2, "page_buff"); if (hp) free((Malloc_t) hp); return; } } - tp = tbuf = (char *) mush_malloc(BUFFER_LEN, "string"); + tp = tbuf = (char *) mush_malloc(BUFFER_LEN, "page_buff"); if (!tbuf) mush_panic("Unable to allocate memory in do_page"); @@ -762,8 +875,8 @@ do_page(dbref player, const char *arg1, const char *arg2, dbref cause, * anyone, this looks like a spam attack. */ if ((gcount+ag_count) == 98) { notify(player, T("You're trying to page too many people at once.")); - mush_free((Malloc_t) tbuf, "string"); - mush_free((Malloc_t) tbuf2, "string"); + mush_free((Malloc_t) tbuf, "page_buff"); + mush_free((Malloc_t) tbuf2, "page_buff"); if (hp) free((Malloc_t) hp); return; @@ -779,8 +892,8 @@ do_page(dbref player, const char *arg1, const char *arg2, dbref cause, if (!gcount && !ag_count) { /* Well, that was a total waste of time. */ - mush_free((Malloc_t) tbuf, "string"); - mush_free((Malloc_t) tbuf2, "string"); + mush_free((Malloc_t) tbuf, "page_buff"); + mush_free((Malloc_t) tbuf2, "page_buff"); if (hp) free((Malloc_t) hp); return; @@ -789,8 +902,8 @@ do_page(dbref player, const char *arg1, const char *arg2, dbref cause, /* Can the player afford to pay for this thing? */ if (!payfor(player, PAGE_COST * (gcount + ag_count))) { notify_format(player, T("You don't have enough %s."), MONIES); - mush_free((Malloc_t) tbuf, "string"); - mush_free((Malloc_t) tbuf2, "string"); + mush_free((Malloc_t) tbuf, "page_buff"); + mush_free((Malloc_t) tbuf2, "page_buff"); if (hp) free((Malloc_t) hp); return; @@ -800,10 +913,10 @@ do_page(dbref player, const char *arg1, const char *arg2, dbref cause, * actually going to someone. We're in this for keeps now. */ /* Evaluate the message if we need to. */ - if (noeval) + if (noeval) { msgbuf = NULL; - else { - mb = msgbuf = (char *) mush_malloc(BUFFER_LEN, "string"); + } else { + mb = msgbuf = (char *) mush_malloc(BUFFER_LEN, "page_buff"); if (!msgbuf) mush_panic("Unable to allocate memory in do_page"); @@ -868,7 +981,7 @@ do_page(dbref player, const char *arg1, const char *arg2, dbref cause, } /* Figure out the 'name' of the player */ - if (PAGE_ALIASES && (alias = shortalias(player)) && *alias) + if ((alias = shortalias(player)) && *alias && PAGE_ALIASES) current = tprintf("%s (%s)", Name(player), alias); else current = (char *) Name(player); diff --git a/src/sql.c b/src/sql.c index 58b8d91..42bc0c0 100644 --- a/src/sql.c +++ b/src/sql.c @@ -3,6 +3,24 @@ * * \brief Code to support PennMUSH connection to SQL databases. * + * Each sql database we support must define its own set of the + * following functions: + * + * penn__sql_init + * penn__sql_connected + * penn__sql_errormsg + * penn__sql_shutdown + * penn__sql_query + * penn__free_sql_query + * + * We define generic functions (named as above, but without _) + * that determine the platform and call the appropriate platform-specific + * function. We also define the softcode interfaces: + * + * fun_sql_escape + * fun_sql + * fun_mapsql + * cmd_sql * */ @@ -13,181 +31,448 @@ #endif #include #include "conf.h" -#ifdef HAS_MYSQL -#include -#include +#ifdef WIN32 +#include +#define sleep Sleep +#endif +#ifdef HAVE_MYSQL +#include +#include +static MYSQL *mysql_connp = NULL; +#endif +#ifdef HAVE_POSTGRESQL +#include +static PGconn *postgres_connp = NULL; +#endif +#ifdef HAVE_SQLITE3 +#include +static sqlite3 *sqlite3_connp = NULL; #endif #include "externs.h" -#include "access.h" #include "log.h" #include "parse.h" -#include "boolexp.h" #include "command.h" #include "function.h" #include "mushdb.h" #include "dbdefs.h" #include "conf.h" #include "confmagic.h" +#include "ansi.h" + +/* Supported platforms */ +typedef enum { SQL_PLATFORM_DISABLED = -1, + SQL_PLATFORM_MYSQL = 1, + SQL_PLATFORM_POSTGRESQL, + SQL_PLATFORM_SQLITE3 +} sqlplatform; + +/* Number of times to try a connection */ +#define SQL_RETRY_TIMES 3 + +#define sql_test_result(qres) \ + if (!qres) { \ + if (affected_rows >= 0) { \ + } else if (!sql_connected()) { \ + safe_str("#-1 SQL ERROR: NO DATABASE CONNECTED", buff, bp); \ + } else { \ + safe_format(buff, bp, "#-1 SQL ERROR: %s", sql_error()); \ + } \ + return; \ + } -#ifdef HAS_MYSQL -static MYSQL *mysql_struct = NULL; -#define MYSQL_RETRY_TIMES 3 - -static MYSQL_RES *sql_query(char *query_str, int *affected_rows); -static void free_sql_query(MYSQL_RES * qres); -void sql_timer(); -static int sql_init(void); -#ifdef _SWMP_ -void sql_startup(); -void sqenv_clear(int); -static int sqllist_check(dbref thing, dbref player, char type, char end, char *str, int just_match); -int sql_env[2]; +#ifdef HAVE_MYSQL +static MYSQL_RES *penn_mysql_sql_query(const char *, int *); +static void penn_mysql_free_sql_query(MYSQL_RES * qres); +static int penn_mysql_sql_init(void); +static void penn_mysql_sql_shutdown(void); +static int penn_mysql_sql_connected(void); #endif -static char sql_up = 0; +#ifdef HAVE_POSTGRESQL +static PGresult *penn_pg_sql_query(const char *, int *); +static void penn_pg_free_sql_query(PGresult * qres); +static int penn_pg_sql_init(void); +static void penn_pg_sql_shutdown(void); +static int penn_pg_sql_connected(void); +#endif +#ifdef HAVE_SQLITE3 +static int penn_sqlite3_sql_init(void); +static void penn_sqlite3_sql_shutdown(void); +static int penn_sqlite3_sql_connected(void); +static sqlite3_stmt *penn_sqlite3_sql_query(const char *, int *); +static void penn_sqlite3_free_sql_query(sqlite3_stmt *); +#endif +static sqlplatform sql_platform(void); -void -sql_shutdown(void) +/* A helper function to translate SQL_PLATFORM into one of our + * supported platform codes. We remember this value, so a reboot + * is necessary to change it. + */ +static sqlplatform +sql_platform(void) { - sql_up = 0; - if (!mysql_struct) - return; - mysql_close(mysql_struct); - mysql_struct = NULL; -} - -void sql_startup() { - sql_init(); - - /* Delete All Entries in Auth_T Table to start with */ - if(mysql_struct) mysql_query(mysql_struct, "DELETE FROM auth_t"); - sql_up = 1; -#ifdef _SWMP_ - sql_env[0] = -1; - sql_env[1] = -1; + static sqlplatform platform = SQL_PLATFORM_DISABLED; +#ifdef HAVE_MYSQL + if (!strcasecmp(SQL_PLATFORM, "mysql")) + platform = SQL_PLATFORM_MYSQL; +#endif +#ifdef HAVE_POSTGRESQL + if (!strcasecmp(SQL_PLATFORM, "postgres")) + platform = SQL_PLATFORM_POSTGRESQL; + if (!strcasecmp(SQL_PLATFORM, "postgresql")) + platform = SQL_PLATFORM_POSTGRESQL; +#endif +#ifdef HAVE_SQLITE3 + if (!strcasecmp(SQL_PLATFORM, "sqlite")) + platform = SQL_PLATFORM_SQLITE3; + if (!strcasecmp(SQL_PLATFORM, "sqlite3")) + platform = SQL_PLATFORM_SQLITE3; #endif + return platform; } +/* Initialize a connection to an SQL database */ static int sql_init(void) { - int retries = MYSQL_RETRY_TIMES; - static time_t last_retry = 0; - time_t curtime; - - /* Only retry at most once per minute. */ - curtime = time(NULL); - if (curtime < (last_retry + 60)) + switch (sql_platform()) { +#ifdef HAVE_MYSQL + case SQL_PLATFORM_MYSQL: + return penn_mysql_sql_init(); +#endif +#ifdef HAVE_POSTGRESQL + case SQL_PLATFORM_POSTGRESQL: + return penn_pg_sql_init(); +#endif +#ifdef HAVE_SQLITE3 + case SQL_PLATFORM_SQLITE3: + return penn_sqlite3_sql_init(); +#endif + default: return 0; - last_retry = curtime; - - /* If we are already connected, drop and retry the connection, in - * case for some reason the server went away. - */ - if (mysql_struct) - sql_shutdown(); - - if (!strcasecmp(SQL_PLATFORM, "mysql")) { - while (retries && !mysql_struct) { - /* Try to connect to the database host. If we have specified - * localhost, use the Unix domain socket instead. - */ - mysql_struct = mysql_init(NULL); - - if (!mysql_real_connect - (mysql_struct, SQL_HOST, SQL_USER, SQL_PASS, SQL_DB, 3306, 0, 0)) { - do_rawlog(LT_ERR, "Failed mysql connection: %s\n", - mysql_error(mysql_struct)); - sql_shutdown(); - sleep(1); - } - retries--; - } } +} - if (mysql_struct) - return 1; - else +/* Check if a connection exists */ +static int +sql_connected(void) +{ + switch (sql_platform()) { +#ifdef HAVE_MYSQL + case SQL_PLATFORM_MYSQL: + return penn_mysql_sql_connected(); +#endif +#ifdef HAVE_POSTGRESQL + case SQL_PLATFORM_POSTGRESQL: + return penn_pg_sql_connected(); +#endif +#ifdef HAVE_SQLITE3 + case SQL_PLATFORM_SQLITE3: + return penn_sqlite3_sql_connected(); +#endif + default: return 0; + } } -static MYSQL_RES * -sql_query(char *q_string, int *affected_rows) +/* Return an error string if needed */ +static const char * +sql_error(void) { - MYSQL_RES *qres; - int fail; - - /* No affected rows by default */ - *affected_rows = -1; - - /* Make sure we have something to query, first. */ - if (!q_string || !*q_string) + switch (sql_platform()) { +#ifdef HAVE_MYSQL + case SQL_PLATFORM_MYSQL: + return mysql_error(mysql_connp); +#endif +#ifdef HAVE_POSTGRESQL + case SQL_PLATFORM_POSTGRESQL: + return PQerrorMessage(postgres_connp); +#endif +#ifdef HAVE_SQLITE3 + case SQL_PLATFORM_SQLITE3: + return sqlite3_errmsg(sqlite3_connp); +#endif + default: return NULL; + } +} - /* If we have no connection, and we don't have auto-reconnect on - * (or we try to auto-reconnect and we fail), return NULL. - */ - if (!mysql_struct) { - sql_init(); - if (!mysql_struct) { - return NULL; - } +/** Shut down a connection to an SQL database */ +void +sql_shutdown(void) +{ + switch (sql_platform()) { +#ifdef HAVE_MYSQL + case SQL_PLATFORM_MYSQL: + penn_mysql_sql_shutdown(); + break; +#endif +#ifdef HAVE_POSTGRESQL + case SQL_PLATFORM_POSTGRESQL: + penn_pg_sql_shutdown(); + break; +#endif +#ifdef HAVE_SQLITE3 + case SQL_PLATFORM_SQLITE3: + penn_sqlite3_sql_shutdown(); + break; +#endif + default: + return; } +} - /* Send the query. If it returns non-zero, we have an error. */ - fail = mysql_real_query(mysql_struct, q_string, strlen(q_string)); - if (fail && (mysql_errno(mysql_struct) == CR_SERVER_GONE_ERROR)) { - /* If it's CR_SERVER_GONE_ERROR, the server went away. - * Try reconnecting. */ - sql_init(); - if (mysql_struct) - fail = mysql_real_query(mysql_struct, q_string, strlen(q_string)); +static void +free_sql_query(void *queryp __attribute__ ((__unused__))) +{ + switch (sql_platform()) { +#ifdef HAVE_MYSQL + case SQL_PLATFORM_MYSQL: + penn_mysql_free_sql_query((MYSQL_RES *) queryp); + break; +#endif +#ifdef HAVE_POSTGRESQL + case SQL_PLATFORM_POSTGRESQL: + penn_pg_free_sql_query((PGresult *) queryp); + break; +#endif +#ifdef HAVE_SQLITE3 + case SQL_PLATFORM_SQLITE3: + penn_sqlite3_free_sql_query((sqlite3_stmt *) queryp); + break; +#endif + default: + return; } - /* If we still fail, it's an error. */ - if (fail) { +} + +static void * +sql_query(const char *query_str __attribute__ ((__unused__)), int *affected_rows + __attribute__ ((__unused__))) +{ + switch (sql_platform()) { +#ifdef HAVE_MYSQL + case SQL_PLATFORM_MYSQL: + return penn_mysql_sql_query(query_str, affected_rows); + break; +#endif +#ifdef HAVE_POSTGRESQL + case SQL_PLATFORM_POSTGRESQL: + return penn_pg_sql_query(query_str, affected_rows); + break; +#endif +#ifdef HAVE_SQLITE3 + case SQL_PLATFORM_SQLITE3: + return penn_sqlite3_sql_query(query_str, affected_rows); +#endif + default: return NULL; + } +} + +FUNCTION(fun_sql_escape) +{ + char bigbuff[BUFFER_LEN * 2 + 1]; + int chars_written; + if (sql_platform() == SQL_PLATFORM_DISABLED) { + safe_str(T(e_disabled), buff, bp); + return; + } + if (!Sql_Ok(executor)) { + safe_str(T(e_perm), buff, bp); + return; + } + if (!args[0] || !*args[0]) + return; + if (!sql_connected()) { + sql_init(); + if (!sql_connected()) { + notify(executor, "No SQL database connection."); + safe_str("#-1", buff, bp); + return; } + } + switch (sql_platform()) { +#ifdef HAVE_MYSQL + case SQL_PLATFORM_MYSQL: + chars_written = + mysql_real_escape_string(mysql_connp, bigbuff, args[0], arglens[0]); + break; +#endif +#ifdef HAVE_POSTGRESQL + case SQL_PLATFORM_POSTGRESQL: + chars_written = + PQescapeStringConn(postgres_connp, bigbuff, args[0], arglens[0], NULL); + break; +#endif +#if defined(HAVE_SQLITE3) && defined(HAVE_MYSQL) + case SQL_PLATFORM_SQLITE3: + /* sqlite3 doesn't have a escape function. Use one of my MySQL's + * if we can. */ + chars_written = mysql_escape_string(bigbuff, args[0], arglens[0]); + break; +#endif + default: + safe_str(T(e_disabled), buff, bp); + return; + } + if (chars_written < BUFFER_LEN) + safe_str(bigbuff, buff, bp); + else + safe_str("#-1 TOO LONG", buff, bp); +} + + +COMMAND(cmd_sql) +{ +#ifdef HAVE_MYSQL + MYSQL_FIELD *fields = NULL; +#endif + void *qres; + int affected_rows = -1; + int rownum; + int numfields; + int numrows; + char *cell = NULL; + char *name = NULL; + char tbuf[BUFFER_LEN]; + char *tbp; + ansi_string *as; + int i; + + qres = sql_query(arg_left, &affected_rows); - /* Get the result */ - qres = mysql_use_result(mysql_struct); if (!qres) { - if (!mysql_field_count(mysql_struct)) { - /* We didn't expect data back, so see if we modified anything */ - *affected_rows = mysql_affected_rows(mysql_struct); - return NULL; + if (affected_rows >= 0) { + notify_format(player, "SQL: %d rows affected.", affected_rows); + } else if (!sql_connected()) { + notify(player, "No SQL database connection."); } else { - /* Oops, we should have had data! */ - return NULL; + notify_format(player, "SQL: Error: %s", sql_error()); } + return; } - return qres; -} -void -free_sql_query(MYSQL_RES * qres) -{ - MYSQL_ROW row_p; - while ((row_p = mysql_fetch_row(qres)) != NULL) ; - mysql_free_result(qres); + /* Get results. A silent query (INSERT, UPDATE, etc.) will return NULL */ + switch (sql_platform()) { +#ifdef HAVE_MYSQL + case SQL_PLATFORM_MYSQL: + affected_rows = mysql_affected_rows(mysql_connp); + numfields = mysql_num_fields(qres); + numrows = INT_MAX; /* Using mysql_use_result() doesn't know the number + of rows ahead of time. */ + fields = mysql_fetch_fields(qres); + break; +#endif +#ifdef HAVE_POSTGRESQL + case SQL_PLATFORM_POSTGRESQL: + numfields = PQnfields(qres); + numrows = PQntuples(qres); + break; +#endif +#ifdef HAVE_SQLITE3 + case SQL_PLATFORM_SQLITE3: + numfields = sqlite3_column_count(qres); + numrows = INT_MAX; + break; +#endif + default: + goto finished; + } + + for (rownum = 0; rownum < numrows; rownum++) { +#ifdef HAVE_MYSQL + MYSQL_ROW row_p = NULL; + if (sql_platform() == SQL_PLATFORM_MYSQL) { + row_p = mysql_fetch_row(qres); + if (!row_p) + break; + } +#endif +#ifdef HAVE_SQLITE3 + if (sql_platform() == SQL_PLATFORM_SQLITE3) { + int retcode = sqlite3_step(qres); + if (retcode == SQLITE_DONE) + break; + else if (retcode != SQLITE_ROW) { + notify_format(player, "SQL: Error: %s", sql_error()); + break; + } + } +#endif + + if (numfields > 0) { + for (i = 0; i < numfields; i++) { + switch (sql_platform()) { +#ifdef HAVE_MYSQL + case SQL_PLATFORM_MYSQL: + cell = row_p[i]; + name = fields[i].name; + break; +#endif +#ifdef HAVE_POSTGRESQL + case SQL_PLATFORM_POSTGRESQL: + cell = PQgetvalue(qres, rownum, i); + name = PQfname(qres, i); + break; +#endif +#ifdef HAVE_SQLITE3 + case SQL_PLATFORM_SQLITE3: + cell = (char *) sqlite3_column_text(qres, i); + name = (char *) sqlite3_column_name(qres, i); + break; +#endif + default: + /* Not reached, shuts up compiler */ + break; + } + if (cell && *cell) { + if (strchr(cell, TAG_START) || strchr(cell, ESC_CHAR)) { + /* Either old or new style ANSI string. */ + tbp = tbuf; + as = parse_ansi_string(cell); + safe_ansi_string(as, 0, as->len, tbuf, &tbp); + *tbp = '\0'; + free_ansi_string(as); + cell = tbuf; + } + } + notify_format(player, "Row %d, Field %s: %s", + rownum + 1, name, (cell && *cell) ? cell : "NULL"); + } + } else + notify_format(player, "Row %d: NULL", rownum + 1); + } + +finished: + free_sql_query(qres); } FUNCTION(fun_mapsql) { - MYSQL_RES *qres; - MYSQL_ROW row_p; + void *qres; ufun_attrib ufun; char *wenv[10]; char *osep = (char *) " "; int affected_rows; int rownum; char numbuff[20]; - int numfields; + int numfields, numrows; char rbuff[BUFFER_LEN]; int funccount = 0; int do_fieldnames = 0; int i; - MYSQL_FIELD *fields; - + char buffs[9][BUFFER_LEN]; + char *tbp; + char *cell = NULL; + ansi_string *as; +#ifdef HAVE_MYSQL + MYSQL_FIELD *fields = NULL; +#endif + if (sql_platform() == SQL_PLATFORM_DISABLED) { + safe_str(T(e_disabled), buff, bp); + return; + } if (!Sql_Ok(executor)) { safe_str(T(e_perm), buff, bp); return; @@ -195,7 +480,6 @@ FUNCTION(fun_mapsql) if (!fetch_ufun_attrib(args[0], executor, &ufun, 1)) return; - if (nargs > 2) { /* we have an output separator in args[2]. */ osep = args[2]; @@ -209,52 +493,128 @@ FUNCTION(fun_mapsql) for (i = 0; i < 10; i++) wenv[i] = NULL; - qres = sql_query(args[1], &affected_rows); - - if (!qres) { - if (affected_rows >= 0) { - notify_format(executor, "SQL: %d rows affected.", affected_rows); - } else if (!mysql_struct) { - notify(executor, "No SQL database connection."); - } else { - notify_format(executor, "SQL: Error: %s", mysql_error(mysql_struct)); - safe_str("#-1", buff, bp); - } - return; - } - + sql_test_result(qres); /* Get results. A silent query (INSERT, UPDATE, etc.) will return NULL */ - numfields = mysql_num_fields(qres); + switch (sql_platform()) { +#ifdef HAVE_MYSQL + case SQL_PLATFORM_MYSQL: + numfields = mysql_num_fields(qres); + numrows = INT_MAX; + break; +#endif +#ifdef HAVE_POSTGRESQL + case SQL_PLATFORM_POSTGRESQL: + numfields = PQnfields(qres); + numrows = PQntuples(qres); + break; +#endif +#ifdef HAVE_SQLITE3 + case SQL_PLATFORM_SQLITE3: + numfields = sqlite3_column_count(qres); + numrows = INT_MAX; + break; +#endif + default: + goto finished; + } if (do_fieldnames) { - fields = mysql_fetch_fields(qres); - strncpy(numbuff, unparse_integer(0), 20); + mush_strncpy(numbuff, unparse_integer(0), 20); wenv[0] = numbuff; +#ifdef HAVE_MYSQL + if (sql_platform() == SQL_PLATFORM_MYSQL) + fields = mysql_fetch_fields(qres); +#endif for (i = 0; i < numfields && i < 9; i++) { - wenv[i + 1] = fields[i].name; + switch (sql_platform()) { +#ifdef HAVE_MYSQL + case SQL_PLATFORM_MYSQL: + wenv[i + 1] = fields[i].name; + break; +#endif +#ifdef HAVE_POSTGRESQL + case SQL_PLATFORM_POSTGRESQL: + wenv[i + 1] = PQfname(qres, i); + break; +#endif +#ifdef HAVE_SQLITE3 + case SQL_PLATFORM_SQLITE3: + wenv[i + 1] = (char *) sqlite3_column_name(qres, i); + break; +#endif + default: + break; + } } if (call_ufun(&ufun, wenv, i + 1, rbuff, executor, enactor, pe_info)) goto finished; safe_str(rbuff, buff, bp); } - rownum = 0; - while ((row_p = mysql_fetch_row(qres)) != NULL) { - if (rownum++ > 0 || do_fieldnames) { + for (rownum = 0; rownum < numrows; rownum++) { +#ifdef HAVE_MYSQL + MYSQL_ROW row_p = NULL; + if (sql_platform() == SQL_PLATFORM_MYSQL) { + row_p = mysql_fetch_row(qres); + if (!row_p) + break; + } +#endif +#ifdef HAVE_SQLITE3 + if (sql_platform() == SQL_PLATFORM_SQLITE3) { + int retcode = sqlite3_step(qres); + if (retcode == SQLITE_DONE) + break; + else if (retcode != SQLITE_ROW) + goto finished; + } +#endif + if (rownum > 0 || do_fieldnames) { safe_str(osep, buff, bp); } - strncpy(numbuff, unparse_integer(rownum), 20); + mush_strncpy(numbuff, unparse_integer(rownum + 1), 20); wenv[0] = numbuff; for (i = 0; (i < numfields) && (i < 9); i++) { - wenv[i + 1] = row_p[i]; + switch (sql_platform()) { +#ifdef HAVE_MYSQL + case SQL_PLATFORM_MYSQL: + cell = row_p[i]; + break; +#endif +#ifdef HAVE_POSTGRESQL + case SQL_PLATFORM_POSTGRESQL: + cell = PQgetvalue(qres, rownum, i); + break; +#endif +#ifdef HAVE_SQLITE3 + case SQL_PLATFORM_SQLITE3: + cell = (char *) sqlite3_column_text(qres, i); + break; +#endif + default: + break; + } + if (cell && *cell) { + if (strchr(cell, TAG_START) || strchr(cell, ESC_CHAR)) { + /* Either old or new style ANSI string. */ + tbp = buffs[i]; + as = parse_ansi_string(cell); + 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]) wenv[i + 1] = (char *) ""; } /* Now call the ufun. */ if (call_ufun(&ufun, wenv, i + 1, rbuff, executor, enactor, pe_info)) goto finished; - if (safe_str(rbuff, buff, bp) && funccount == pe_info->fun_invocations) + if (safe_str(rbuff, buff, bp) + && funccount == pe_info->fun_invocations) goto finished; funccount = pe_info->fun_invocations; } @@ -264,60 +624,118 @@ finished: FUNCTION(fun_sql) { - MYSQL_RES *qres; - MYSQL_ROW row_p; + void *qres; char *rowsep = (char *) " "; char *fieldsep = (char *) " "; + char tbuf[BUFFER_LEN], *tbp; + char *cell = NULL; int affected_rows; int rownum; int i; - int numfields; - + int numfields, numrows; + ansi_string *as; + if (sql_platform() == SQL_PLATFORM_DISABLED) { + safe_str(T(e_disabled), buff, bp); + return; + } if (!Sql_Ok(executor)) { safe_str(T(e_perm), buff, bp); return; } if (nargs >= 2) { - /* we have a row separator in args[2]. */ + /* we have a row separator in args[1]. */ rowsep = args[1]; } if (nargs >= 3) { - /* we have a field separator in args[3]. */ + /* we have a field separator in args[2]. Got to parse it */ fieldsep = args[2]; } qres = sql_query(args[0], &affected_rows); - - if (!qres) { - if (affected_rows >= 0) { - notify_format(executor, "SQL: %d rows affected.", affected_rows); - } else if (!mysql_struct) { - notify(executor, "No SQL database connection."); - } else { - notify_format(executor, "SQL: Error: %s", mysql_error(mysql_struct)); - safe_str("#-1", buff, bp); - } - return; - } - + sql_test_result(qres); /* Get results. A silent query (INSERT, UPDATE, etc.) will return NULL */ - numfields = mysql_num_fields(qres); + switch (sql_platform()) { +#ifdef HAVE_MYSQL + case SQL_PLATFORM_MYSQL: + numfields = mysql_num_fields(qres); + numrows = INT_MAX; + break; +#endif +#ifdef HAVE_POSTGRESQL + case SQL_PLATFORM_POSTGRESQL: + numfields = PQnfields(qres); + numrows = PQntuples(qres); + break; +#endif +#ifdef HAVE_SQLITE3 + case SQL_PLATFORM_SQLITE3: + numfields = sqlite3_column_count(qres); + numrows = INT_MAX; + break; +#endif + default: + goto finished; + } - rownum = 0; - while ((row_p = mysql_fetch_row(qres)) != NULL) { - if (rownum++ > 0) { - safe_str(rowsep, buff, bp); + for (rownum = 0; rownum < numrows; rownum++) { +#ifdef HAVE_MYSQL + MYSQL_ROW row_p = NULL; + if (sql_platform() == SQL_PLATFORM_MYSQL) { + row_p = mysql_fetch_row(qres); + if (!row_p) + break; + } +#endif +#ifdef HAVE_SQLITE3 + if (sql_platform() == SQL_PLATFORM_SQLITE3) { + int retcode = sqlite3_step(qres); + if (retcode == SQLITE_DONE) + break; + else if (retcode != SQLITE_ROW) + break; } +#endif + if (rownum > 0) + safe_str(rowsep, buff, bp); for (i = 0; i < numfields; i++) { if (i > 0) { if (safe_str(fieldsep, buff, bp)) goto finished; } - if (row_p[i] && *row_p[i]) - if (safe_str(row_p[i], buff, bp)) + switch (sql_platform()) { +#ifdef HAVE_MYSQL + case SQL_PLATFORM_MYSQL: + cell = row_p[i]; + break; +#endif +#ifdef HAVE_POSTGRESQL + case SQL_PLATFORM_POSTGRESQL: + cell = PQgetvalue(qres, rownum, i); + break; +#endif +#ifdef HAVE_SQLITE3 + case SQL_PLATFORM_SQLITE3: + cell = (char *) sqlite3_column_text(qres, i); + break; +#endif + default: + break; + } + if (cell && *cell) { + if (strchr(cell, TAG_START) || strchr(cell, ESC_CHAR)) { + /* Either old or new style ANSI string. */ + tbp = tbuf; + as = parse_ansi_string(cell); + safe_ansi_string(as, 0, as->len, tbuf, &tbp); + *tbp = '\0'; + free_ansi_string(as); + cell = tbuf; + } + if (safe_str(cell, buff, bp)) goto finished; /* We filled the buffer, best stop */ + } } } finished: @@ -325,359 +743,318 @@ finished: } -FUNCTION(fun_sql_escape) -{ - char bigbuff[BUFFER_LEN * 2 + 1]; - if (!Sql_Ok(executor)) { - safe_str(T(e_perm), buff, bp); - return; - } +/* MYSQL-specific functions */ +#ifdef HAVE_MYSQL - if (!args[0] || !*args[0]) +static void +penn_mysql_sql_shutdown(void) +{ + if (!mysql_connp) return; - - if (!mysql_struct) { - sql_init(); - if (!mysql_struct) { - notify(executor, "No SQL database connection."); - safe_str("#-1", buff, bp); - return; - } - } - if (mysql_real_escape_string(mysql_struct, bigbuff, args[0], strlen(args[0])) - < BUFFER_LEN) - safe_str(bigbuff, buff, bp); - else - safe_str("#-1 TOO LONG", buff, bp); + mysql_close(mysql_connp); + mysql_connp = NULL; } - -COMMAND (cmd_sql) { - MYSQL_RES *qres; - MYSQL_ROW row_p; - int affected_rows; - int rownum; - int numfields; - char *cell; - MYSQL_FIELD *fields; - int i; - - qres = sql_query(arg_left, &affected_rows); - - if (!qres) { - if (affected_rows >= 0) { - notify_format(player, "SQL: %d rows affected.", affected_rows); - } else if (!mysql_struct) { - notify(player, "No SQL database connection."); - } else { - notify_format(player, "SQL: Error: %s", mysql_error(mysql_struct)); - } - return; - } - - /* Get results. A silent query (INSERT, UPDATE, etc.) will return NULL */ - numfields = mysql_num_fields(qres); - fields = mysql_fetch_fields(qres); - - rownum = 0; - while ((row_p = mysql_fetch_row(qres)) != NULL) { - rownum++; - if (numfields > 0) { - for (i = 0; i < numfields; i++) { - cell = row_p[i]; - notify_format(player, "Row %d, Field %s: %s", - rownum, fields[i].name, (cell && *cell) ? cell : "NULL"); - } - } else - notify_format(player, "Row %d: NULL", rownum); - } - free_sql_query(qres); +static int +penn_mysql_sql_connected(void) +{ + return mysql_connp ? 1 : 0; } -#ifdef _SWMP_ /* SWM Protocol */ -/* Do secondly checks on Authentication Table & Query Tables */ -void sql_timer() { - /* query variables */ - MYSQL_RES *qres, *qres2; - MYSQL_ROW row_p, row_p2; - int num_rows = 0 , got_rows = 0, got_fields = 0; - int got_fields2 = 0, got_rows2 = 0; - int i, j; - char *str; - char buf[BUFFER_LEN]; - dbref player; - - qres = NULL; - qres2 = NULL; - - if(!sql_up || !GoodObject(SQLCMD_MasterRoom)) - return; - - if(!mysql_struct) { - if((mudtime % 60) == 0) { /* If its down, try every minute to get it back up. */ - sql_init(); - if(!mysql_struct) - return; - } else return; - } - - /* Before we do anything lets delete old shit */ - - mysql_query(mysql_struct, tprintf("DELETE FROM auth_t WHERE last < %d", mudtime-1800)); - - /* We're connected.. Check Authentication Table */ - got_rows = mysql_query(mysql_struct, "SELECT * FROM auth_t WHERE authcode=0"); - - if(got_rows != 0) { - do_log(LT_ERR, 0, 0, "SQL-> (%s:%d) %s", __FILE__, __LINE__, mysql_error(mysql_struct)); - goto query_table; - } - - qres = mysql_store_result(mysql_struct); - if (qres == NULL) { - /* Oops, we should have had data! */ - if(!mysql_field_count(mysql_struct)) - goto query_table; - } - - got_rows = mysql_num_rows(qres); - if(got_rows < 1) - goto query_table; - - got_fields = mysql_num_fields(qres); - - if(got_fields < 6 || got_fields > 6) { - do_log(LT_ERR, 0, 0, "SQL 'auth_t' table %s fields.", got_fields < 6 ? "not enough" : "too many"); - goto query_table; - } - - for(i = 0, row_p = mysql_fetch_row(qres) ; i < got_rows ; i++, row_p = mysql_fetch_row(qres)) { - if((player = lookup_player(row_p[4])) == NOTHING || - !Site_Can_Connect((const char *) row_p[1],player ) || - !password_check(player, (const char *)row_p[5])) { - /* Mark this row as bad auth, can't find user */ - j = -1; - } else j = 1; - - if( mysql_query(mysql_struct, - tprintf("UPDATE auth_t SET authcode=%d, pass=\"LOGGEDIN\", user=\"%d\" WHERE last = %d AND id = %d", - j, player, atoi(row_p[3]), atoi(row_p[0]))) != 0) - do_log(LT_ERR, 0, 0, "SQL-> (%s/%d) %s ", __FILE__, __LINE__, mysql_error(mysql_struct)); - } -query_table: - if(qres != NULL) mysql_free_result(qres); +static int +penn_mysql_sql_init(void) +{ + int retries = SQL_RETRY_TIMES; + static time_t last_retry = 0; + char sql_host[BUFFER_LEN], *p; + int sql_port = 3306; + time_t curtime; - /* Check Query Table */ - got_rows = mysql_query(mysql_struct, "SELECT * FROM query_t WHERE io=1"); + /* Only retry at most once per minute. */ + curtime = time(NULL); + if (curtime < (last_retry + 60)) + return 0; + last_retry = curtime; - if(got_rows != 0) { - do_log(LT_ERR, 0, 0, "SQL -> %d/%s : %s", __LINE__, __FILE__, mysql_error(mysql_struct)); - goto st_finish; - } + /* If we are already connected, drop and retry the connection, in + * case for some reason the server went away. + */ + if (sql_connected()) + sql_shutdown(); - qres = mysql_store_result(mysql_struct); + /* Parse SQL_HOST into sql_host and sql_port */ + mush_strncpy(sql_host, SQL_HOST, BUFFER_LEN); + if ((p = strchr(sql_host, ':'))) { + *p++ = '\0'; + sql_port = atoi(p); + if (!sql_port) + sql_port = 3306; + } - if(qres == NULL) { - do_log(LT_ERR, 0 , 0, "SQL: Error(%s:%d): %s", __FILE__, __LINE__, mysql_error(mysql_struct)); - return; - } + while (retries && !mysql_connp) { + /* Try to connect to the database host. If we have specified + * localhost, use the Unix domain socket instead. + */ + mysql_connp = mysql_init(NULL); + + if (!mysql_real_connect + (mysql_connp, sql_host, SQL_USER, SQL_PASS, SQL_DB, sql_port, 0, 0)) { + do_rawlog(LT_ERR, "Failed mysql connection: %s\n", + mysql_error(mysql_connp)); + sql_shutdown(); + sleep(1); + } + retries--; + } - got_rows = mysql_num_rows(qres); + return sql_connected(); +} - if(got_rows < 1) - goto st_finish; - got_fields = mysql_num_fields(qres); - if(!got_fields) - goto st_finish; - if(got_fields < 4 || got_fields > 4) { - do_log(LT_ERR, 0, 0, "SQL 'query_t' table %s fields.", got_fields < 4 ? "not enough" : "too many"); - goto st_finish; - } +static MYSQL_RES * +penn_mysql_sql_query(const char *q_string, int *affected_rows) +{ + MYSQL_RES *qres; + int fail; - for(i = 0, row_p = mysql_fetch_row(qres); i < got_rows && row_p != NULL ; i++, row_p = mysql_fetch_row(qres)) { - sql_env[0] = atoi(row_p[0]); - sql_env[1] = atoi(row_p[1]); - /* Load AUTHID we're assosciated with */ - got_rows2 = mysql_query(mysql_struct, - tprintf("SELECT * FROM auth_t WHERE id = %d", atoi(row_p[1]))); - if(got_rows2 != 0) { - /* Update Return Result As No Authorized user logged in */ - mysql_query(mysql_struct, tprintf("UPDATE query_t SET io=0, query=\"%s\" WHERE id = %d", mysql_error(mysql_struct),atoi(row_p[0]) )); - continue; + if (affected_rows) + *affected_rows = -1; - } - qres2 = mysql_store_result(mysql_struct); + /* Make sure we have something to query, first. */ + if (!q_string || !*q_string) + return NULL; - /* Not in auth_t table */ - if(qres2 == NULL) { - mysql_query(mysql_struct, tprintf("UPDATE query_t SET io=0, query=\"%s\" WHERE id = %d", mysql_error(mysql_struct), atoi(row_p[0]) )); - continue; - } + /* If we have no connection, and we don't have auto-reconnect on + * (or we try to auto-reconnect and we fail), return NULL. + */ + if (!sql_connected()) { + sql_init(); + if (!sql_connected()) { + return NULL; + } + } - got_rows2 = mysql_num_rows(qres2); + /* Send the query. If it returns non-zero, we have an error. */ + fail = mysql_real_query(mysql_connp, q_string, strlen(q_string)); + if (fail && (mysql_errno(mysql_connp) == CR_SERVER_GONE_ERROR)) { + /* If it's CR_SERVER_GONE_ERROR, the server went away. + * Try reconnecting. */ + sql_init(); + if (mysql_connp) + fail = mysql_real_query(mysql_connp, q_string, strlen(q_string)); + } + /* If we still fail, it's an error. */ + if (fail) { + return NULL; + } - if(got_rows2 < 1) { - /* Update Return Result As No Authorized user logged in */ - mysql_free_result(qres2); - mysql_query(mysql_struct, tprintf("UPDATE query_t SET io=0, query=\"not logged in\" WHERE id = %d", atoi(row_p[0]) )); - continue; - } - /* Fucked up auth_t Table*/ - if(got_rows > 1) { - mysql_free_result(qres2); - mysql_query(mysql_struct, tprintf("UPDATE query_t SET io=0, query=\"ERROR: Identical User IDs logged in.\" WHERE id = %d", atoi(row_p[0]) )); - continue; - } - row_p2 = mysql_fetch_row(qres2); - - player = atoi(row_p2[4]); - /* They Aren't Real */ - if(!GoodObject(player) || !IsPlayer(player)) { - mysql_free_result(qres2); - mysql_query(mysql_struct, tprintf("UPDATE query_t SET io=0, query=\"ERROR: NonExistent Player ID logged into.\" WHERE id = %d", atoi(row_p[0]) )); - /* Delete Auth Table ID Entry , they shouldn't be there*/ - mysql_query(mysql_struct, tprintf("DELETE FROM auth_t WHERE user=\"%d\"", player)); - /* Delete Us Too */ - continue; + /* Get the result */ + qres = mysql_use_result(mysql_connp); + if (!qres) { + if (mysql_field_count(mysql_connp) == 0) { + /* We didn't expect data back, so see if we modified anything */ + if (affected_rows) + *affected_rows = mysql_affected_rows(mysql_connp); + return NULL; + } else { + /* Oops, we should have had data! */ + return NULL; + } + } + return qres; +} - } +static void +penn_mysql_free_sql_query(MYSQL_RES * qres) +{ + MYSQL_ROW row_p; + while ((row_p = mysql_fetch_row(qres)) != NULL) ; + mysql_free_result(qres); +} - memset(buf, '\0', BUFFER_LEN); - strncpy(buf, row_p[3], BUFFER_LEN-1); - j = sqllist_check(Contents(SQLCMD_MasterRoom), player, '$', ':', buf, 0); - if(j < 1) { - mysql_free_result(qres2); - mysql_query(mysql_struct, tprintf("UPDATE query_t SET query=\"-1\", io=0 WHERE id = %d", atoi(row_p[0]) )); - continue; - } - mysql_free_result(qres2); +#endif - sql_env[0] = -1; - sql_env[1] = -1; - } - sql_env[0] = -1; - sql_env[1] = -1; -st_finish: - if(qres != NULL) mysql_free_result(qres); - if(qres2 != NULL) mysql_free_result(qres2); +#ifdef HAVE_POSTGRESQL +static void +penn_pg_sql_shutdown(void) +{ + if (!sql_connected()) + return; + PQfinish(postgres_connp); + postgres_connp = NULL; } -int -sqllist_check(dbref thing, dbref player, char type, char end, char *str, - int just_match) +static int +penn_pg_sql_connected(void) { - int match = 0; - - while (thing != NOTHING) { - if (atr_comm_match(thing, player, type, end, str, just_match, NULL, NULL, NULL)) - match = 1; - else - match = 0; - - thing = Next(thing); - } - return (match); + return postgres_connp ? 1 : 0; } -/* SQ_Respond() - the way commands queued will respond to this type of query */ -FUNCTION(fun_sq_respond) { - MYSQL_RES *qres; - int got_rows; +static int +penn_pg_sql_init(void) +{ + int retries = SQL_RETRY_TIMES; + static time_t last_retry = 0; + char sql_host[BUFFER_LEN], *p; + char sql_port[BUFFER_LEN]; + time_t curtime; + /* Only retry at most once per minute. */ + curtime = time(NULL); + if (curtime < (last_retry + 60)) + return 0; + last_retry = curtime; - /* SQL Environment should be set to use this function, if not deny usage */ - if(sql_env[0] == -1 || sql_env[1] == -1) { - safe_str("#-1 NOTHING TO RESPOND TO", buff, bp); - return; - } + /* If we are already connected, drop and retry the connection, in + * case for some reason the server went away. + */ + if (sql_connected()) + sql_shutdown(); - if(!sql_up) { - safe_str("#-1 SQL Server Down", buff, bp); - return; + /* Parse SQL_HOST into sql_host and sql_port */ + mush_strncpy(sql_host, SQL_HOST, BUFFER_LEN); + strcpy(sql_port, "5432"); + if ((p = strchr(sql_host, ':'))) { + *p++ = '\0'; + if (*p) + strcpy(sql_port, p); } - if(!mysql_struct) { - sql_init(); - if(!mysql_struct) { - safe_str("#-1 SQL Server Down", buff, bp); - return; + while (retries && !postgres_connp) { + /* Try to connect to the database host. */ + char conninfo[BUFFER_LEN]; + snprintf(conninfo, BUFFER_LEN, + "host=%s port=%s dbname=%s user=%s password=%s", sql_host, + sql_port, SQL_DB, SQL_USER, SQL_PASS); + postgres_connp = PQconnectdb(conninfo); + if (PQstatus(postgres_connp) != CONNECTION_OK) { + do_rawlog(LT_ERR, "Failed postgresql connection to %s: %s\n", + PQdb(postgres_connp), PQerrorMessage(postgres_connp)); + sql_shutdown(); + sleep(1); } + retries--; } - /* For some reason we're having some unfreed result here.. */ - mysql_free_result(mysql_store_result(mysql_struct)); - got_rows = mysql_query(mysql_struct, tprintf("SELECT * FROM query_t WHERE id = %d", sql_env[0])); - if(got_rows != 0) { - safe_str(tprintf("#-1 %s", mysql_error(mysql_struct)), buff, bp); - return; - } - mysql_free_result(mysql_store_result(mysql_struct)); - - /* Ok.. We do Exist, now Update */ + return sql_connected(); +} - got_rows = - mysql_query(mysql_struct, tprintf("UPDATE query_t SET io = 0, query = \"%s\" WHERE id = %d", args[0], sql_env[0])); +static PGresult * +penn_pg_sql_query(const char *q_string, int *affected_rows) +{ + PGresult *qres; - if(got_rows != 0) { - safe_format(buff, bp, "#-1 %s", mysql_error(mysql_struct)); - return; - } - safe_chr('1', buff, bp); -} + /* No affected rows by default */ + if (affected_rows) + *affected_rows = -1; -void sqenv_clear(int id) { + /* Make sure we have something to query, first. */ + if (!q_string || !*q_string) + return NULL; - sql_env[0] = -1; - sql_env[0] = -1; + /* If we have no connection, and we don't have auto-reconnect on + * (or we try to auto-reconnect and we fail), return NULL. + */ + if (!sql_connected()) { + sql_init(); + if (!sql_connected()) { + return NULL; + } + } - if(!mysql_struct) { + /* Send the query. If it returns non-zero, we have an error. */ + qres = PQexec(postgres_connp, q_string); + if (!qres || (PQresultStatus(qres) != PGRES_COMMAND_OK && + PQresultStatus(qres) != PGRES_TUPLES_OK)) { + /* Serious error, try one more time */ sql_init(); - if(!mysql_struct) - return; + if (sql_connected()) + qres = PQexec(postgres_connp, q_string); + if (!qres || (PQresultStatus(qres) != PGRES_COMMAND_OK && + PQresultStatus(qres) != PGRES_TUPLES_OK)) { + return NULL; + } } - mysql_query(mysql_struct, tprintf("UPDATE query_t SET io = 0 WHERE id = %d", id)); -} + if (PQresultStatus(qres) == PGRES_COMMAND_OK) { + *affected_rows = atoi(PQcmdTuples(qres)); + return NULL; + } -#else -FUNCTION(fun_sq_respond) { + return qres; } -void sql_timer() { +static void +penn_pg_free_sql_query(PGresult * qres) +{ + PQclear(qres); } -#endif - -#else +#endif /* HAVE_POSTGRESQL */ -/* Oops, no SQL */ +#ifdef HAVE_SQLITE3 -FUNCTION(fun_sql) +static int +penn_sqlite3_sql_init(void) { - safe_str(T(e_disabled), buff, bp); + + sqlite3_connp = NULL; + if (sqlite3_open(SQL_DB, &sqlite3_connp) != SQLITE_OK) { + do_rawlog(LT_ERR, "sqlite3: Failed to open %s: %s", SQL_DB, sql_error()); + if (sqlite3_connp) { + sqlite3_close(sqlite3_connp); + sqlite3_connp = NULL; + } + return 0; + } else + return 1; } -FUNCTION(fun_mapsql) +static void +penn_sqlite3_sql_shutdown(void) { - safe_str(T(e_disabled), buff, bp); + sqlite3_close(sqlite3_connp); + sqlite3_connp = NULL; } -FUNCTION(fun_sql_escape) +static int +penn_sqlite3_sql_connected(void) { - safe_str(T(e_disabled), buff, bp); + return sqlite3_connp ? 1 : 0; } -/* Do secondly checks on Authentication Table & Query Tables */ -void sql_timer() { - return; +static sqlite3_stmt * +penn_sqlite3_sql_query(const char *query, int *affected_rows) +{ + int q_len, retcode; + const char *eoq = NULL; + sqlite3_stmt *statement = NULL; + + if (!sql_connected()) { + sql_init(); + if (!sql_connected()) + return NULL; + } + + q_len = strlen(query); +#if SQLITE3_VERSION_NUMBER >= 30003010 + retcode = sqlite3_prepare_v2(sqlite3_connp, query, q_len, &statement, &eoq); +#else + retcode = sqlite3_prepare(sqlite3_connp, query, q_len, &statement, &eoq); +#endif + + *affected_rows = -1; /* Can't find this out yet */ + + if (retcode == SQLITE_OK) + return statement; + else + return NULL; } -void -sql_shutdown(void) +static void +penn_sqlite3_free_sql_query(sqlite3_stmt * stmt) { - return; + sqlite3_finalize(stmt); } - -#endif +#endif /* HAVE_SQLITE3 */ diff --git a/src/strdup.c b/src/strdup.c index b2ebc08..6ff8009 100644 --- a/src/strdup.c +++ b/src/strdup.c @@ -16,7 +16,7 @@ #include "mymalloc.h" #include "confmagic.h" -#ifndef HAS_STRDUP +#ifndef HAVE_STRDUP char *strdup(const char *s); /** strdup for systems without one. diff --git a/src/strtree.c b/src/strtree.c index b08ad58..372a658 100644 --- a/src/strtree.c +++ b/src/strtree.c @@ -142,11 +142,11 @@ st_stats(dbref player, StrTree *root, const char *name) bytes = (sizeof(StrNode) - BUFFER_LEN) * root->count + root->mem; st_traverse_stats(root->root, &maxdepth, &mindepth, &avgdepth, &leaves, - &perms, &nperms); - notify_format(player, "%-10s %7ld %7d %6d %4d %4d %9lu %11.3f %7lu", - name, root->count, leaves, mindepth, maxdepth, - avgdepth, perms, - ((double) nperms / (double) (root->count - perms)), bytes); + &perms, &nperms); + notify_format(player, "%-10s %7d %7d %6d %4d %4d %9lu %11.3f %7lu", + name, (int) root->count, leaves, mindepth, maxdepth, + avgdepth, perms, + ((double) nperms / (double) (root->count - perms)), bytes); } /* Tree rotations. These preserve left-to-right ordering, @@ -530,6 +530,25 @@ st_delete(char const *s, StrTree *root) root->count--; } +static void +st_node_walk(StrNode *node, STFunc callback, void *data) +{ + if (node->left) + st_node_walk(node->left, callback, data); + callback(node->string, node->info >> ST_COLOR, data); + if (node->right) + st_node_walk(node->right, callback, data); +} + +/** Call a function for each node in the tree, in-order */ +void +st_walk(StrTree *tree, STFunc callback, void *data) +{ + if (!tree || !tree->root) + return; + st_node_walk(tree->root, callback, data); +} + /* Print the tree, for debugging purposes. */ static void st_print_tree(StrNode *node, int tree_depth, int lead) @@ -588,7 +607,7 @@ st_depth_helper(StrNode *node, int *maxdepth, int *mindepth, if (node->info >= ST_USE_LIMIT) (*perms)++; else - (*nperms) += node->info; + (*nperms) += node->info >> ST_COLOR; if (count > *maxdepth) *maxdepth = count; diff --git a/src/strutil.c b/src/strutil.c index 328f3b1..6b262e0 100644 --- a/src/strutil.c +++ b/src/strutil.c @@ -8,30 +8,31 @@ #include "config.h" +#include #include #include #include #include #include +#ifdef HAVE_INTTYPES_H +#include +#endif #include "copyrite.h" #include "conf.h" #include "case.h" -#include "ansi.h" #include "pueblo.h" #include "parse.h" #include "externs.h" +#include "ansi.h" #include "mymalloc.h" #include "log.h" #include "confmagic.h" -char *next_token(char *str, char sep); -int format_long(long val, char *buff, char **bp, int maxlen, int base); -static char * -mush_strndup(const char *src, size_t len, const char *check) - __attribute_malloc__; +int format_long(intmax_t val, char *buff, char **bp, int maxlen, int base); /* Duplicate the first len characters of s */ - static char *mush_strndup(const char *src, size_t len, const char *check) +char * +mush_strndup(const char *src, size_t len, const char *check) { char *copy; size_t rlen = strlen(src); @@ -48,6 +49,7 @@ mush_strndup(const char *src, size_t len, const char *check) return copy; } + /** Our version of strdup, with memory leak checking. * This should be used in preference to strdup, and in assocation * with mush_free(). @@ -60,7 +62,7 @@ mush_strdup(const char *s, const char *check __attribute__ ((__unused__))) { char *x; -#ifdef HAS_STRDUP +#ifdef HAVE_STRDUP x = strdup(s); if (x) add_check(check); @@ -74,7 +76,22 @@ mush_strdup(const char *s, const char *check __attribute__ ((__unused__))) return x; } +#ifdef HAVE__VSNPRINTF_S +/** Wrapper for the Win32 _snprintf_s() function */ +int +sane_snprintf_s(char *str, size_t len, const char *fmt, ...) +{ + va_list args; + int ret; + va_start(args, fmt); + ret = _vsnprintf_s(str, len, _TRUNCATE, fmt, args); + va_end(args); + return ret; +} +#endif + /** Return the string chopped at lim characters. + * lim must be <= BUFFER_LEN * \param str string to chop. * \param lim character at which to chop the string. * \return statically allocated buffer with chopped string. @@ -85,14 +102,14 @@ chopstr(const char *str, size_t lim) static char tbuf1[BUFFER_LEN]; if (strlen(str) <= lim) return (char *) str; - strncpy(tbuf1, str, lim); - tbuf1[lim] = '\0'; + if (lim >= BUFFER_LEN) + lim = BUFFER_LEN; + mush_strncpy(tbuf1, str, lim); return tbuf1; } -#ifndef HAS_STRCASECMP -#ifndef WIN32 +#if !defined(HAVE_STRCASECMP) && !defined(HAVE__STRICMP) /** strcasecmp for systems without it. * \param s1 one string to compare. * \param s2 another string to compare. @@ -108,7 +125,9 @@ strcasecmp(const char *s1, const char *s2) return (DOWNCASE(*s1) - DOWNCASE(*s2)); } +#endif +#if !defined(HAVE_STRNCASECMP) && !defined(HAVE__STRNICMP) /** strncasecmp for systems without it. * \param s1 one string to compare. * \param s2 another string to compare. @@ -128,10 +147,9 @@ strncasecmp(const char *s1, const char *s2, size_t n) return 0; } -#endif /* !WIN32 */ -#endif /* !HAS_STRCASECMP */ +#endif -/** Does string begin with prefix? +/** Does string begin with prefix? * This comparison is case-insensitive. * \param string to check. * \param prefix to check against. @@ -164,11 +182,9 @@ string_match(const char *src, const char *sub) if (string_prefix(src, sub)) return src; /* else scan to beginning of next word */ - while (*src && (isalpha((unsigned char) *src) - || isdigit((unsigned char) *src))) + while (*src && isalnum((unsigned char) *src)) src++; - while (*src && !isalpha((unsigned char) *src) - && !isdigit((unsigned char) *src)) + while (*src && !isalnum((unsigned char) *src)) src++; } } @@ -210,7 +226,7 @@ strupper(const char *s) buf1[0] = '\0'; return buf1; } - strcpy(buf1, s); + mush_strncpy(buf1, s, BUFFER_LEN); for (p = buf1; *p; p++) *p = UPCASE(*p); return buf1; @@ -230,7 +246,7 @@ strlower(const char *s) buf1[0] = '\0'; return buf1; } - strcpy(buf1, s); + mush_strncpy(buf1, s, BUFFER_LEN); for (p = buf1; *p; p++) *p = DOWNCASE(*p); return buf1; @@ -579,7 +595,7 @@ safe_accent(const char *RESTRICT base, const char *RESTRICT tmplate, size_t len, /** Define the args used in APPEND_TO_BUF */ -#define APPEND_ARGS int len, blen, clen +#define APPEND_ARGS size_t len, blen, clen /** Append a string c to the end of buff, starting at *bp. * This macro is used by the safe_XXX functions. */ @@ -641,7 +657,7 @@ safe_format(char *buff, char **bp, const char *RESTRICT fmt, ...) * \return 0 on success, non-zero on failure. */ int -safe_integer(long i, char *buff, char **bp) +safe_integer(intmax_t i, char *buff, char **bp) { return format_long(i, buff, bp, BUFFER_LEN, 10); } @@ -653,9 +669,9 @@ safe_integer(long i, char *buff, char **bp) * \return 0 on success, non-zero on failure. */ int -safe_uinteger(unsigned long i, char *buff, char **bp) +safe_uinteger(uintmax_t i, char *buff, char **bp) { - return safe_str(unparse_uinteger(i), buff, bp); + return safe_str(unparse_integer(i), buff, bp); } /** Safely store an unsigned integer into a short buffer. @@ -665,7 +681,7 @@ safe_uinteger(unsigned long i, char *buff, char **bp) * \return 0 on success, non-zero on failure. */ int -safe_integer_sbuf(long i, char *buff, char **bp) +safe_integer_sbuf(intmax_t i, char *buff, char **bp) { return format_long(i, buff, bp, SBUF_LEN, 10); } @@ -765,13 +781,15 @@ safe_str_space(const char *c, char *buff, char **bp) * \retval 1 failure. */ int -safe_strl(const char *s, int len, char *buff, char **bp) +safe_strl(const char *s, size_t len, char *buff, char **bp) { - int blen, clen; + size_t blen, clen; if (!s || !*s) return 0; - if (len == 1) + if (len == 0) + return 0; + else if (len == 1) return safe_chr(*s, buff, bp); blen = *bp - buff; @@ -839,8 +857,9 @@ skip_space(const char *s) return c; } +#ifndef HAVE_STRCHRNUL /** Return a pointer to next char in s which matches c, or to the terminating - * null at the end of s. + * nul at the end of s. * \param s string to search. * \param c character to search for. * \return pointer to next occurence of c or to the end of s. @@ -849,30 +868,36 @@ char * seek_char(const char *s, char c) { char *p = (char *) s; - while (p && *p && (*p != c)) + if (!p) + return NULL; + while (*p && (*p != c)) p++; return p; } +#endif /** Unsigned char version of strlen. * \param s string. * \return length of s. */ -int +size_t u_strlen(const unsigned char *s) { return strlen((const char *) s); } -/** Unsigned char version of strcpy. Equally dangerous. +/** Unsigned char version of mush_strncpy(). Destination string + * is nul-terminated. * \param target destination for copy. * \param source string to copy. + * \param len maximum number of bytes to copy. * \return pointer to copy. */ unsigned char * -u_strcpy(unsigned char *target, const unsigned char *source) +u_strncpy(unsigned char *target, const unsigned char *source, size_t len) { - return (unsigned char *) strcpy((char *) target, (const char *) source); + return (unsigned char *) mush_strncpy((char *) target, (const char *) source, + len); } /** Search for all copies of old in string, and replace each with newbit. @@ -883,15 +908,15 @@ u_strcpy(unsigned char *target, const unsigned char *source) * \return allocated string with replacements performed. */ char * -replace_string(const char *RESTRICT old, const char *RESTRICT newbit, - const char *RESTRICT string) +replace_string(const char *restrict old, const char *restrict newbit, + const char *restrict string) { char *result, *r; size_t len, newlen; r = result = mush_malloc(BUFFER_LEN, "replace_string.buff"); if (!result) - mush_panic(T("Couldn't allocate memory in replace_string!")); + mush_panic("Couldn't allocate memory in replace_string!"); len = strlen(old); newlen = strlen(newbit); @@ -911,38 +936,13 @@ replace_string(const char *RESTRICT old, const char *RESTRICT newbit, return result; } -char * -str_escaped_chr(const char *RESTRICT string, char escape_chr) -{ - const char *p; - char *result, *r; - - r = result = mush_malloc(BUFFER_LEN, "str_escaped_chr.buff"); - if (!result) - mush_panic(T("Couldn't allocate memory in replace_string!")); - - p = string; - while(*p) { - if(*p == '\\') - *r++ = '\\'; - else if(*p == escape_chr) - *r++ = '\\'; - *r++ = *p++; - } - - - *r = '\0'; - return result; -} - - /** Standard replacer tokens for text and position */ const char *standard_tokens[2] = { "##", "#@" }; /* Replace two tokens in a string at once. All-around better than calling * replace_string() twice */ -/** Search for all copies of two old strings, and replace each with a +/** Search for all copies of two old strings, and replace each with a * corresponding newbit. * The replaced string is returned, newly allocated. * \param old array of two strings to find. @@ -952,7 +952,7 @@ const char *standard_tokens[2] = { "##", "#@" }; */ char * replace_string2(const char *old[2], const char *newbits[2], - const char *RESTRICT string) + const char *restrict string) { char *result, *rp; char firsts[3] = { '\0', '\0', '\0' }; @@ -963,7 +963,7 @@ replace_string2(const char *old[2], const char *newbits[2], rp = result = mush_malloc(BUFFER_LEN, "replace_string.buff"); if (!result) - mush_panic(T("Couldn't allocate memory in replace_string2!")); + mush_panic("Couldn't allocate memory in replace_string2!"); firsts[0] = old[0][0]; firsts[1] = old[1][0]; @@ -979,17 +979,17 @@ replace_string2(const char *old[2], const char *newbits[2], safe_strl(string, skip, result, &rp); string += skip; } - if(*string) { - if (strncmp(string, old[0], oldlens[0]) == 0) { /* Copy the first */ - safe_strl(newbits[0], newlens[0], result, &rp); - string += oldlens[0]; - } else if (strncmp(string, old[1], oldlens[1]) == 0) { /* The second */ - safe_strl(newbits[1], newlens[1], result, &rp); - string += oldlens[1]; - } else { - safe_chr(*string, result, &rp); - string++; - } + if (*string) { + if (strncmp(string, old[0], oldlens[0]) == 0) { /* Copy the first */ + safe_strl(newbits[0], newlens[0], result, &rp); + string += oldlens[0]; + } else if (strncmp(string, old[1], oldlens[1]) == 0) { /* The second */ + safe_strl(newbits[1], newlens[1], result, &rp); + string += oldlens[1]; + } else { + safe_chr(*string, result, &rp); + string++; + } } } @@ -998,6 +998,29 @@ replace_string2(const char *old[2], const char *newbits[2], } +/* Copy a string up until a specific character (Or end of string.) + * Replaces the strcpy()/strchr()/*p=0 pattern. + * Input and output buffers shouldn't overlap. + * + * \param dest buffer to copy into. + * \param src string to copy from. + * \param c character to stop at. + * \return pointer to the start of the string + */ +char * +copy_up_to(char *RESTRICT dest, const char *RESTRICT src, char c) +{ + char *d; + d = dest; + + for (d = dest; *src && *src != c; src++) + *d++ = *src; + + *d = '\0'; + + return dest; +} + /** Given a string and a separator, trim leading and trailing spaces * if the separator is a space. This destructively modifies the string. * \param str string to trim. @@ -1017,7 +1040,7 @@ trim_space_sep(char *str, char sep) str += strspn(str, " "); for (p = str; *p; p++) ; /* And trailing */ - for (p--; (p > str) && (*p == ' '); p--) ; + for (p--; p > str && *p == ' '; p--) ; p++; *p = '\0'; return str; @@ -1034,8 +1057,22 @@ next_token(char *str, char sep) { /* move pointer to start of the next token */ - while (*str && (*str != sep)) + while (*str) { + if (*str == sep) { + break; + } + switch (*str) { + case TAG_START: + while (*str && *str != TAG_END) + str++; + break; + case ESC_CHAR: + while (*str && *str != 'm') + str++; + break; + } str++; + } if (!*str) return NULL; str++; @@ -1095,66 +1132,6 @@ do_wordcount(char *str, char sep) return n; } -/** A version of strlen that ignores ansi and HTML sequences. - * \param p string to get length of. - * \return length of string p, not including ansi/html sequences. - */ -int -ansi_strlen(const char *p) -{ - int i = 0; - - if (!p) - return 0; - - while (*p) { - if (*p == ESC_CHAR) { - while ((*p) && (*p != 'm')) - p++; - } else if (*p == TAG_START) { - while ((*p) && (*p != TAG_END)) - p++; - } else { - i++; - } - p++; - } - return i; -} - -/** Returns the apparent length of a string, up to numchars visible - * characters. The apparent length skips over nonprinting ansi and - * tags. - * \param p string. - * \param numchars maximum size to report. - * \return apparent length of string. - */ -int -ansi_strnlen(const char *p, size_t numchars) -{ - int i = 0; - - if (!p) - return 0; - while (*p && numchars > 0) { - if (*p == ESC_CHAR) { - while ((*p) && (*p != 'm')) { - p++; - i++; - } - } else if (*p == TAG_START) { - while ((*p) && (*p != TAG_END)) { - p++; - i++; - } - } else - numchars--; - i++; - p++; - } - return i; -} - /** Given a string, a word, and a separator, remove first occurence * of the word from the string. Destructive. * \param list a string containing a separated list. @@ -1228,81 +1205,30 @@ next_in_list(const char **head) } -/** Strip all ansi and html markup from a string. As a side effect, - * stores the length of the stripped string in a provided address. - * NOTE! Length returned is length *including* the terminating NULL, - * because we usually memcpy the result. - * \param orig string to strip. - * \param s_len address to store length of stripped string, if provided. - * \return pointer to static buffer containing stripped string. - */ -char * -remove_markup(const char *orig, size_t * s_len) -{ - static char buff[BUFFER_LEN]; - char *bp = buff; - const char *q; - size_t len = 0; - - if (!orig) { - if (s_len) - *s_len = 0; - return NULL; - } - - for (q = orig; *q;) { - switch (*q) { - case ESC_CHAR: - /* Skip over ansi */ - while (*q && *q++ != 'm') ; - break; - case TAG_START: - /* Skip over HTML */ - while (*q && *q++ != TAG_END) ; - break; - default: - safe_chr(*q++, buff, &bp); - len++; - } - } - *bp = '\0'; - if (s_len) - *s_len = len + 1; - return buff; -} +#ifndef HAVE_IMAXDIV +typedef struct imaxdiv_t { + intmax_t rem; + intmax_t quot; +} imaxdiv_t; +#endif -/** Safe version of strncpy() that always nul-terminates the - * destination string. The only reason it's not called - * safe_strncpy() is to avoid confusion with the unrelated - * safe_*() pennstr functions. - * \param dst the destination string to copy to - * \param src the source string to copy from - * \param len the maximum number of bytes to copy - * return dst - */ -char * -mush_strncpy(char *RESTRICT dst, const char *RESTRICT src, size_t len) +#ifndef HAVE_IMAXDIV +imaxdiv_t +imaxdiv(intmax_t num, intmax_t denom) { - size_t n = 0; - char *start = dst; - - if (!src || !dst || len == 0) - return dst; - - len--; - - while (*src && n < len) { - *dst++ = *src++; - n++; + imaxdiv_t r; + r.quot = num / denom; + r.rem = num % denom; + if (num >= 0 && r.rem < 0) { + r.quot++; + r.rem -= denom; } - - *dst = '\0'; - return start; + return r; } - +#endif /* !HAVE_IMAXDIV */ /** Safely append an int to a string. Returns a true value on failure. - * This will someday take extra arguments for use with our version + * This will someday take extra arguments for use with our version * of snprintf. Please try not to use it. * maxlen = total length of string. * buf[maxlen - 1] = place where \0 will go. @@ -1310,18 +1236,18 @@ mush_strncpy(char *RESTRICT dst, const char *RESTRICT src, size_t len) * \param val value to append. * \param buff string to append to. * \param bp pointer to pointer to insertion point in buff. - * \param maxlen total length of string. + * \param maxlen total length of string. * \param base the base to render the number in. */ int -format_long(long val, char *buff, char **bp, int maxlen, int base) +format_long(intmax_t val, char *buff, char **bp, int maxlen, int base) { char stack[128]; /* Even a negative 64 bit number will only be 21 digits or so max. This should be plenty of buffer room. */ char *current; int size = 0, neg = 0; - ldiv_t r; + imaxdiv_t r; const char *digits = "0123456789abcdefghijklmnopqrstuvwxyz"; /* Sanity checks */ @@ -1341,13 +1267,25 @@ format_long(long val, char *buff, char **bp, int maxlen, int base) if (val < 0) { /* -LONG_MIN == LONG_MIN on 2's complement systems. Take the easy way out since this value is rarely encountered. */ + + /* Most of these defaults are probably wrong on Win32. I hope it + has at least the headers from C99. */ +#ifndef PRIdMAX +#define PRIdMAX "lld" +#endif +#ifndef PRIxMAX +#define PRIxMAX "llx" +#endif +#ifndef PRIoMAX +#define PRIoMAX "llo" +#endif switch (base) { case 10: - return safe_format(buff, bp, "%ld", val); + return safe_format(buff, bp, "%" PRIdMAX, val); case 16: - return safe_format(buff, bp, "%lx", val); + return safe_format(buff, bp, "%" PRIxMAX, val); case 8: - return safe_format(buff, bp, "%lo", val); + return safe_format(buff, bp, "%" PRIoMAX, val); default: /* Weird base /and/ LONG_MIN. Fix someday. */ return 0; @@ -1365,7 +1303,7 @@ format_long(long val, char *buff, char **bp, int maxlen, int base) /* ldiv(x, y) does x/y and x%y at the same time (both of * which we need). */ - r = ldiv(r.quot, base); + r = imaxdiv(r.quot, base); *(--current) = digits[r.rem]; } while (r.quot); @@ -1380,7 +1318,6 @@ format_long(long val, char *buff, char **bp, int maxlen, int base) size = stack + sizeof(stack) - current; - /* if (size < (int) ((buff + maxlen - 1) - *bp)) { */ if (((int) (*bp - buff)) + size < maxlen - 2) { switch (size % 8) { case 0: @@ -1414,7 +1351,7 @@ format_long(long val, char *buff, char **bp, int maxlen, int base) return 0; } -#if defined(HAS_STRXFRM) && !defined(WIN32) +#ifndef HAVE__STRNCOLL /** A locale-sensitive strncmp. * \param s1 first string to compare. * \param s2 second string to compare. @@ -1426,6 +1363,7 @@ format_long(long val, char *buff, char **bp, int maxlen, int base) int strncoll(const char *s1, const char *s2, size_t t) { +#ifdef HAVE_STRXFRM char *d1, *d2, *ns1, *ns2; int result; size_t s1_len, s2_len; @@ -1444,11 +1382,18 @@ strncoll(const char *s1, const char *s2, size_t t) (void) strxfrm(d1, ns1, s1_len); (void) strxfrm(d2, ns2, s2_len); result = strcmp(d1, d2); + mush_free(ns1, "string"); + mush_free(ns2, "string"); mush_free(d1, "string"); mush_free(d2, "string"); return result; +#else + return strncmp(s1, s2, t); +#endif } +#endif +#ifndef HAVE__STRICOLL /** A locale-sensitive strcasecmp. * \param s1 first string to compare. * \param s2 second string to compare. @@ -1459,6 +1404,7 @@ strncoll(const char *s1, const char *s2, size_t t) int strcasecoll(const char *s1, const char *s2) { +#ifdef HAVE_STRXFRM char *d1, *d2; int result; size_t s1_len, s2_len; @@ -1474,8 +1420,13 @@ strcasecoll(const char *s1, const char *s2) mush_free(d1, "string"); mush_free(d2, "string"); return result; +#else + return strcasecmp(s1, s2); +#endif } +#endif +#ifndef HAVE__STRNICOLL /** A locale-sensitive strncasecmp. * \param s1 first string to compare. * \param s2 second string to compare. @@ -1487,6 +1438,7 @@ strcasecoll(const char *s1, const char *s2) int strncasecoll(const char *s1, const char *s2, size_t t) { +#ifdef HAVE_STRXFRM char *d1, *d2, *ns1, *ns2; int result; size_t s1_len, s2_len; @@ -1505,412 +1457,44 @@ strncasecoll(const char *s1, const char *s2, size_t t) (void) strxfrm(d1, strupper(ns1), s1_len); (void) strxfrm(d2, strupper(ns2), s2_len); result = strcmp(d1, d2); + mush_free(ns1, "string"); + mush_free(ns2, "string"); mush_free(d1, "string"); mush_free(d2, "string"); return result; +#else + return strncasecmp(s1, s2, t); +#endif } -#endif /* HAS_STRXFRM && !WIN32 */ +#endif -/** Return a string pointer past any ansi/html markup at the start. - * \param p a string. - * \return pointer to string after any initial ansi/html markup. +/** Safe version of strncpy() that always nul-terminates the + * destination string. The only reason it's not called + * safe_strncpy() is to avoid confusion with the unrelated + * safe_*() pennstr functions. + * \param dst the destination string to copy to + * \param src the source string to copy from + * \param len the maximum number of bytes to copy + * \return dst */ char * -skip_leading_ansi(const char *p) +mush_strncpy(char *restrict dst, const char *restrict src, size_t len) { - if (!p) - return NULL; - while (*p == ESC_CHAR || *p == TAG_START) { - if (*p == ESC_CHAR) { - while (*p && *p != 'm') - p++; - } else { /* TAG_START */ - while (*p && *p != TAG_END) - p++; - } - if (*p) - p++; - } - return (char *) p; - -} - -/** Convert a string into an ansi_string. - * This takes a string that may contain ansi/html markup codes and - * converts it to an ansi_string structure that separately stores - * the plain string and the markup codes for each character. - * \param src string to parse. - * \return pointer to an ansi_string structure representing the src string. - */ -ansi_string * -parse_ansi_string(const char *src) -{ - ansi_string *data; - char *y, *current = NULL; - size_t p = 0; - - if (!src) - return NULL; - - data = mush_malloc(sizeof *data, "ansi_string"); - if (!data) - return NULL; - - data->len = ansi_strlen(src); - - while (*src) { - y = skip_leading_ansi(src); - if (y != src) { - if (current) - mush_free(current, "markup_codes"); - current = mush_strndup(src, y - src, "markup_codes"); - src = y; - } - if (current) - data->codes[p] = mush_strdup(current, "markup_codes"); - else - data->codes[p] = NULL; - data->text[p] = *src; - if (*src) - src++; - p++; - } - data->text[p] = '\0'; - - while (p <= data->len) { - data->codes[p] = NULL; - p++; - } - - if (current) - mush_free(current, "markup_codes"); - - return data; -} - - -/** Fill up an ansi_string with codes so that when a code starts it - * applies to all the following characters until there's a new code. - * \param as pointer to an ansi_string to populate codes in. - */ -void -populate_codes(ansi_string *as) -{ - size_t p; - char *current = NULL; - - if (!as) - return; - - for (p = 0; p < as->len; p++) - if (as->codes[p]) { - if (current) - mush_free(current, "markup_codes"); - current = mush_strdup(as->codes[p], "markup_codes"); - } else { - if (!current) - current = mush_strdup(ANSI_NORMAL, "markup_codes"); - as->codes[p] = mush_strdup(current, "markup_codes"); - } - if (current) - mush_free(current, "markup_codes"); -} - -/** Strip out codes from an ansi_string, leaving in only the codes where - * they change. - * \param as pointer to an ansi_string. - */ -void -depopulate_codes(ansi_string *as) -{ - size_t p, m; - int normal = 1; - - if (!as) - return; - - for (p = 0; p <= as->len; p++) { - if (as->codes[p]) { - if (normal) { - if (strcmp(as->codes[p], ANSI_NORMAL) == 0) { - mush_free(as->codes[p], "markup_codes"); - as->codes[p] = NULL; - continue; - } else { - normal = 0; - } - } - - m = p; - for (p++; p < as->len; p++) { - if (as->codes[p] && strcmp(as->codes[p], as->codes[m]) == 0) { - mush_free(as->codes[p], "markup_codes"); - as->codes[p] = NULL; - } else { - p--; - break; - } - } - } - } -} - -/** Reverse an ansi string, preserving its ansification. - * This function destructively modifies the ansi_string passed. - * \param as pointer to an ansi string. - */ -void -flip_ansi_string(ansi_string *as) -{ - int p, n; - - populate_codes(as); - - for (p = 0, n = as->len - 1; p < n; p++, n--) { - char *tcode; - char t; - - tcode = as->codes[p]; - t = as->text[p]; - as->codes[p] = as->codes[n]; - as->text[p] = as->text[n]; - as->codes[n] = tcode; - as->text[n] = t; - } -} - - -static int is_ansi_code(const char *s); -static int is_start_html_code(const char *s) __attribute__ ((__unused__)); -static int is_end_html_code(const char *s); -/** Is s a string that signifies the end of ANSI codes? */ -#define is_end_ansi_code(s) (!strcmp((s),ANSI_NORMAL)) - - -static int -is_ansi_code(const char *s) -{ - return s && *s == ESC_CHAR; -} - -static int -is_start_html_code(const char *s) -{ - return s && *s == TAG_START && *(s + 1) != '/'; -} - -static int -is_end_html_code(const char *s) -{ - return s && *s == TAG_START && *(s + 1) == '/'; -} - -/** Free an ansi_string. - * \param as pointer to ansi_string to free. - */ -void -free_ansi_string(ansi_string *as) -{ - int p; - - if (!as) - return; - for (p = as->len; p >= 0; p--) { - if (as->codes[p]) - mush_free(as->codes[p], "markup_codes"); - } - mush_free(as, "ansi_string"); -} - -/** Safely append an ansi_string into a buffer as a real string. - * \param as pointer to ansi_string to append. - * \param start position in as to start copying from. - * \param len length in characters to copy from as. - * \param buff buffer to insert into. - * \param bp pointer to pointer to insertion point of buff. - * \retval 0 success. - * \retval 1 failure. - */ -int safe_ansi_string(ansi_string *as, size_t start, size_t len, char *buff, char **bp) { - int p, q; - int in_ansi = 0; - int in_html = 0; - - if (!as) - return 1; - - depopulate_codes(as); - - if (start > as->len || len == 0 || as->len == 0) - return safe_str("", buff, bp); - - /* Find the starting codes by working our way backward until we - * reach some opening codes, and then working our way back from there - * until we hit a non-opening code or non-code - */ - p = start; - while ((p >= 0) && (as->codes[p] == NULL)) - p--; - /* p is now either <0 or pointing to a code */ - if ((p >= 0) && !is_end_html_code(as->codes[p]) && - !is_end_ansi_code(as->codes[p])) { - /* p is now pointing to a starting code */ - q = p; - while ((q >= 0) && as->codes[q] && !is_end_html_code(as->codes[q]) && - !is_end_ansi_code(as->codes[q])) { - if (is_ansi_code(as->codes[q])) - in_ansi = 1; - else if (is_start_html_code(as->codes[q])) - in_html++; - q--; - } - /* p is now pointing to the first starting code, and we know if we're - * in ansi, html, or both. We also know how many html tags have been - * opened. - */ - } - - /* Copy the text. The right thing to do now would be to have a stack - * of open html tags and clear in_html once all of the tags have - * been closed. We don't quite do that, alas. - */ - for (p = (int) start; p < (int) (start + len) && p < (int) as->len; p++) { - if (as->codes[p]) { - if (safe_str(as->codes[p], buff, bp)) - return 1; - if (is_end_ansi_code(as->codes[p])) - in_ansi = 0; - else if (is_ansi_code(as->codes[p])) - in_ansi = 1; - if (is_end_html_code(as->codes[p])) - in_html--; - else if (is_start_html_code(as->codes[p])) - in_html++; - } - if (safe_chr(as->text[p], buff, bp)) - return 1; - } - - /* Output (only) closing codes if needed. */ - while (p <= (int) as->len) { - if (!in_ansi && !in_html) - break; - if (as->codes[p]) { - if (is_end_ansi_code(as->codes[p])) { - in_ansi = 0; - if (safe_str(as->codes[p], buff, bp)) - return 1; - } else if (is_end_html_code(as->codes[p])) { - in_html--; - if (safe_str(as->codes[p], buff, bp)) - return 1; - } - } - p++; - } - if (in_ansi) - safe_str(ANSI_NORMAL, buff, bp); - return 0; -} - -/** Safely append an ansi_string into a buffer as a real string, - * with extra copying of starting tags (for wrap()/align()). - * \param as pointer to ansi_string to append. - * \param start position in as to start copying from. - * \param len length in characters to copy from as. - * \param buff buffer to insert into. - * \param bp pointer to pointer to insertion point of buff. - * \retval 0 success. - * \retval 1 failure. - */ -int safe_ansi_string2(ansi_string *as, size_t start, size_t len, char *buff, char **bp) { - int p, q; - int in_ansi = 0; - int in_html = 0; - - if (!as) - return 1; - - depopulate_codes(as); - - if (start > as->len || len == 0 || as->len == 0) - return safe_str("", buff, bp); + size_t n = 0; + char *start = dst; - /* Find the starting codes by working our way backward until we - * reach some opening codes, and then working our way back from there - * until we hit a non-opening code or non-code - */ - p = start; - while ((p >= 0) && (as->codes[p] == NULL)) - p--; - /* p is now either <0 or pointing to a code */ - if ((p >= 0) && !is_end_html_code(as->codes[p]) && - !is_end_ansi_code(as->codes[p])) { - /* p is now pointing to a starting code */ - q = p; - while ((q >= 0) && as->codes[q] && !is_end_html_code(as->codes[q]) && - !is_end_ansi_code(as->codes[q])) { - if (is_ansi_code(as->codes[q])) - in_ansi = 1; - else if (is_start_html_code(as->codes[q])) - in_html++; - q--; - } - /* p is now pointing to the first starting code, and we know if we're - * in ansi, html, or both. We also know how many html tags have been - * opened. - */ + if (!src || !dst || len == 0) + return dst; - /* Except there's this one problem - Now we know it, we weren't - * doing anything with it. - */ - for (q = q + 1; q <= p; q++) { - if (safe_str(as->codes[q], buff, bp)) - return 1; - } - } + len--; - /* Copy the text. The right thing to do now would be to have a stack - * of open html tags and clear in_html once all of the tags have - * been closed. We don't quite do that, alas. - */ - for (p = (int) start; p < (int) (start + len) && p < (int) as->len; p++) { - if (as->codes[p]) { - if (safe_str(as->codes[p], buff, bp)) - return 1; - if (is_end_ansi_code(as->codes[p])) - in_ansi = 0; - else if (is_ansi_code(as->codes[p])) - in_ansi = 1; - if (is_end_html_code(as->codes[p])) - in_html--; - else if (is_start_html_code(as->codes[p])) - in_html++; - } - if (safe_chr(as->text[p], buff, bp)) - return 1; + while (*src && n < len) { + *dst++ = *src++; + n++; } - /* Output (only) closing codes if needed. */ - while (p <= (int) as->len) { - if (!in_ansi && !in_html) - break; - if (as->codes[p]) { - if (is_end_ansi_code(as->codes[p])) { - in_ansi = 0; - if (safe_str(as->codes[p], buff, bp)) - return 1; - } else if (is_end_html_code(as->codes[p])) { - in_html--; - if (safe_str(as->codes[p], buff, bp)) - return 1; - } - } - p++; - } - if (in_ansi) - safe_str(ANSI_NORMAL, buff, bp); - return 0; + *dst = '\0'; + return start; } /** Safely append a list item to a buffer, possibly with punctuation @@ -1957,7 +1541,7 @@ safe_itemizer(int cur_num, int done, const char *delim, const char *conjoin, * \return a pointer to a static buffer with the stringified time. */ char * -show_time(time_t t, int utc) +show_time(time_t t, bool utc) { struct tm *when; @@ -1983,15 +1567,33 @@ show_tm(struct tm *when) if (!when) return NULL; - strcpy(buffer, asctime(when)); + memset(buffer, '\0', BUFFER_LEN); + mush_strncpy(buffer, asctime(when), BUFFER_LEN); + + return buffer; +} + +char * +str_escaped_chr(const char *RESTRICT string, char escape_chr) +{ + const char *p; + char *result, *r; - p = strlen(buffer) - 1; - if (buffer[p] == '\n') - buffer[p] = '\0'; + r = result = mush_malloc(BUFFER_LEN, "str_escaped_chr.buff"); + if (!result) + mush_panic(T("Couldn't allocate memory in replace_string!")); + + p = string; + while(*p) { + if(*p == '\\') + *r++ = '\\'; + else if(*p == escape_chr) + *r++ = '\\'; + *r++ = *p++; + } - if (buffer[8] == ' ') - buffer[8] = '0'; - return buffer; + *r = '\0'; + return result; } diff --git a/src/tables.c b/src/tables.c index a8c3cf6..e483bf9 100644 --- a/src/tables.c +++ b/src/tables.c @@ -40,6 +40,49 @@ signed char qreg_indexes[256] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; +char from_base_64[256] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, 62, -1, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, + -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, 63, + -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 +}; + +char to_base_64[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; + +char from_base_36[256] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 +}; + +char to_base_36[] = "0123456789abcdefghijklmnopqrstuvwxyz"; + char active_table[256] = { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, @@ -135,6 +178,25 @@ char escaped_chars_s[256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; +char valid_ansi_codes[256] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, + 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + typedef struct { const char *base; const char *entity; @@ -300,7 +362,7 @@ accent_info accent_table[256] = { {NULL, NULL}, {NULL, NULL}, {NULL, NULL}, -{NULL, NULL}, +{" ", " "}, {"!", "¡"}, {NULL, NULL}, {NULL, NULL}, diff --git a/src/timer.c b/src/timer.c index 8fee2d0..50f99b0 100644 --- a/src/timer.c +++ b/src/timer.c @@ -16,6 +16,9 @@ #include #ifdef I_SYS_TIME #include +#ifdef TIME_WITH_SYS_TIME +#include +#endif #else #include #endif @@ -159,10 +162,10 @@ migrate_stuff(int amount) if (!refs || actual > refs_size) { if (refs) - mush_free((Malloc_t) refs, "migration reference array"); + mush_free(refs, "migration reference array"); refs = - (chunk_reference_t **) mush_malloc(actual * sizeof(chunk_reference_t *), - "migration reference array"); + mush_calloc(actual, sizeof(chunk_reference_t *), + "migration reference array"); refs_size = actual; if (!refs) mush_panic("Could not allocate migration reference array"); @@ -357,7 +360,7 @@ start_cpu_timer(void) time_limit.it_interval.tv_sec = 0; time_limit.it_interval.tv_usec = 0; if (setitimer(ITIMER_PROF, &time_limit, NULL)) { - perror("setitimer"); + penn_perror("setitimer"); timer_set = 0; } } else @@ -387,7 +390,7 @@ reset_cpu_timer(void) time_limit.it_interval.tv_sec = 0; time_limit.it_interval.tv_usec = 0; if (setitimer(ITIMER_PROF, &time_limit, &time_left)) - perror("setitimer"); + penn_perror("setitimer"); #elif defined(WIN32) KillTimer(NULL, timer_id); #endif diff --git a/src/unparse.c b/src/unparse.c index ac01c5e..ce3c956 100644 --- a/src/unparse.c +++ b/src/unparse.c @@ -10,6 +10,11 @@ #include "config.h" #include +#ifdef HAVE_INTTYPES_H +#include +#endif +#include + #include "conf.h" #include "externs.h" #include "mushdb.h" @@ -152,7 +157,7 @@ real_unparse(dbref player, dbref loc, int obey_myopic, int use_nameformat, bp = buf; if (ANSI_NAMES && ShowAnsi(player)) safe_format(buf, &bp, "%s%s%s(#%d%s)", ANSI_HILITE, tbuf1, - ANSI_NORMAL, loc, unparse_flags(loc, player)); + ANSI_END, loc, unparse_flags(loc, player)); else safe_format(buf, &bp, "%s(#%d%s)", tbuf1, loc, unparse_flags(loc, player)); @@ -161,7 +166,7 @@ real_unparse(dbref player, dbref loc, int obey_myopic, int use_nameformat, /* show only the name */ if (ANSI_NAMES && ShowAnsi(player)) { bp = buf; - safe_format(buf, &bp, "%s%s%s", ANSI_HILITE, tbuf1, ANSI_NORMAL); + safe_format(buf, &bp, "%s%s%s", ANSI_HILITE, tbuf1, ANSI_END); *bp = '\0'; } else strcpy(buf, tbuf1); @@ -255,7 +260,7 @@ unparse_dbref(dbref num) * \return address of static buffer containing stringified value. */ char * -unparse_integer(long num) +unparse_integer(intmax_t num) { static char str[SBUF_LEN]; char *strp; @@ -271,11 +276,14 @@ unparse_integer(long num) * \return address of static buffer containing stringified value. */ char * -unparse_uinteger(unsigned long num) +unparse_uinteger(uintmax_t num) { - static char str[16]; - - sprintf(str, "%lu", num); + static char str[128]; +#ifndef PRIuMAX + /* Probably not right */ +#define PRIuMAX "lld" +#endif + sprintf(str, "%" PRIuMAX, num); return str; } diff --git a/src/utils.c b/src/utils.c index c8d4c73..c2f5740 100644 --- a/src/utils.c +++ b/src/utils.c @@ -32,6 +32,9 @@ #include #include /* For GetCurrentProcessId() */ #endif +#ifdef HAVE_STDINT_H +#include +#endif #include #include "conf.h" @@ -53,46 +56,12 @@ extern struct module_entry_t *module_list; dbref find_entrance(dbref door); void initialize_mt(void); -unsigned int genrand_int32(void); +uint32_t genrand_int32(void); static void init_genrand(unsigned long); static void init_by_array(unsigned long *, int); extern int local_can_interact_first(dbref from, dbref to, int type); extern int local_can_interact_last(dbref from, dbref to, int type); -/** 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. - */ -Malloc_t -mush_malloc(size_t size, const char *check) -{ - Malloc_t ptr; - add_check(check); - ptr = malloc(size); - if (ptr == NULL) - do_log(LT_ERR, 0, 0, "mush_malloc failed to malloc %ld bytes for %s", - size, 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(Malloc_t RESTRICT ptr, const char *RESTRICT check - __attribute__ ((__unused__))) -{ - 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, @@ -149,7 +118,7 @@ parse_anon_attrib(dbref player, char *str, dbref *thing, ATTR **attrib) AL_CREATOR(*attrib) = player; AL_NAME(*attrib) = mush_strdup("#lambda", "anon_attr.lambda"); t = compress(str); - (*attrib)->data = chunk_create(t, (u_int_16) u_strlen(t), 0); + (*attrib)->data = chunk_create(t, u_strlen(t), 0); free(t); AL_RLock(*attrib) = AL_WLock(*attrib) = TRUE_BOOLEXP; AL_FLAGS(*attrib) = AF_ANON; @@ -177,10 +146,15 @@ free_anon_attrib(ATTR *attrib) /** 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; @@ -226,7 +200,7 @@ fetch_ufun_attrib(char *attrname, dbref executor, ufun_attrib * ufun, pe_flags |= PE_DEBUG; /* Populate the ufun object */ - strncpy(ufun->contents, atr_value(attrib), BUFFER_LEN); + mush_strncpy(ufun->contents, atr_value(attrib), BUFFER_LEN); ufun->thing = thing; ufun->pe_flags = pe_flags; @@ -252,7 +226,7 @@ fetch_ufun_attrib(char *attrname, dbref executor, ufun_attrib * ufun, * \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) { @@ -264,13 +238,9 @@ call_ufun(ufun_attrib * ufun, char **wenv_args, int wenv_argc, char *ret, int pe_ret; char const *ap; - int old_re_subpatterns; - int *old_re_offsets; - char *old_re_from; + struct re_save rsave; - old_re_subpatterns = global_eval_context.re_subpatterns; - old_re_offsets = global_eval_context.re_offsets; - old_re_from = global_eval_context.re_from; + save_regexp_context(&rsave); /* Make sure we have a ufun first */ if (!ufun) @@ -294,6 +264,7 @@ call_ufun(ufun_attrib * ufun, char **wenv_args, int wenv_argc, char *ret, /* Set all the regexp patterns to NULL so they are not * propogated */ + global_eval_context.re_code = NULL; global_eval_context.re_subpatterns = -1; global_eval_context.re_offsets = NULL; global_eval_context.re_from = NULL; @@ -318,9 +289,119 @@ call_ufun(ufun_attrib * ufun, char **wenv_args, int wenv_argc, char *ret, } /* Restore regexp patterns */ - global_eval_context.re_offsets = old_re_offsets; - global_eval_context.re_subpatterns = old_re_subpatterns; - global_eval_context.re_from = old_re_from; + restore_regexp_context(&rsave); + + return pe_ret; +} + +/** Given a thing, attribute, enactor and arguments for %0-%9, + * call the ufun with appropriate permissions on values given for + * wenv_args. The value returned is stored in the buffer pointed to + * by ret, if given. + * \param thing The thing that has the attribute to be called + * \param attrname The name of the attribute to call. + * \param wenv_args An array of string values for global_eval_context.wenv + * \param wenv_argc The number of wenv args to use. + * \param ret If desired, a pointer to a buffer in which the results + * of the process_expression are stored in. + * \param enactor The enactor. + * \param pe_info The pe_info passed to the FUNCTION + * \retval 0 success + * \retval 1 No such attribute, or failed. + */ +bool +call_attrib(dbref thing, const char *attrname, const char *wenv_args[], + int wenv_argc, char *ret, dbref enactor, PE_Info *pe_info) +{ + char atrbuf[BUFFER_LEN]; + char rbuff[BUFFER_LEN]; + char *rp; + char *old_wenv[10]; + int old_args = 0; + int i; + int pe_ret; + char const *ap; + ATTR *attrib; + char *saver[NUMQ]; + + struct re_save rsave; + + /* Make sure we have a valid object to call first */ + if (!GoodObject(thing) || IsGarbage(thing)) + return 1; + + if (attrname == NULL || !*attrname) + return 1; + + /* Fetch the attrib contents */ + attrib = (ATTR *) atr_get(thing, attrname); + if (attrib == NULL) + return 1; + + mush_strncpy(atrbuf, atr_value(attrib), BUFFER_LEN); + + if (!*atrbuf) { + if (ret) + *ret = '\0'; + return 0; + } + + save_global_regs("localize", saver); + + /* Store regepx info */ + save_regexp_context(&rsave); + + /* If the user doesn't care about the return of the expression, + * then use our own rbuff. + */ + if (!ret) + ret = rbuff; + rp = ret; + + /* Set up %0-%9 */ + for (i = 0; i < wenv_argc; i++) { + old_wenv[i] = global_eval_context.wenv[i]; + global_eval_context.wenv[i] = (char *) wenv_args[i]; + } + for (; i < 10; i++) { + old_wenv[i] = global_eval_context.wenv[i]; + global_eval_context.wenv[i] = NULL; + } + /* Clear all q-regs */ + for (i = 0; i < NUMQ; i++) { + global_eval_context.renv[i][0] = '\0'; + } + + /* Set all the regexp patterns to NULL so they are not + * propogated */ + global_eval_context.re_code = NULL; + global_eval_context.re_subpatterns = -1; + global_eval_context.re_offsets = NULL; + global_eval_context.re_from = NULL; + + /* And now, make the call! =) */ + if (pe_info) { + old_args = pe_info->arg_count; + pe_info->arg_count = wenv_argc; + } + + ap = atrbuf; + pe_ret = process_expression(ret, &rp, &ap, thing, thing, + enactor, PE_DEFAULT, PT_DEFAULT, pe_info); + *rp = '\0'; + + /* Restore the old wenv */ + for (i = 0; i < 10; i++) { + global_eval_context.wenv[i] = old_wenv[i]; + } + + if (pe_info) { + pe_info->arg_count = old_args; + } + + /* Restore regexp patterns */ + restore_regexp_context(&rsave); + restore_global_regs("localize", saver); return pe_ret; } @@ -379,7 +460,7 @@ remove_first(dbref first, dbref what) * \retval 1 found thing on list. * \retval 0 did not find thing on list. */ -int +bool member(dbref thing, dbref list) { DOLIST(list, list) { @@ -402,7 +483,7 @@ member(dbref thing, dbref list) * \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 { @@ -425,7 +506,7 @@ recursive_member(dbref disallow, dbref from, int count) * \retval 1 object or location is unfindable. * \retval 0 neither object nor location is unfindable. */ -int +bool unfindable(dbref thing) { int count = 0; @@ -595,7 +676,7 @@ init_by_array(unsigned long init_key[], int key_length) } /* generates a random number on [0,0xffffffff]-interval */ -unsigned int +uint32_t genrand_int32(void) { unsigned long y; @@ -699,8 +780,7 @@ fullalias(dbref it) return n; } - strncpy(n, atr_value(a), BUFFER_LEN - 1); - n[BUFFER_LEN - 1] = '\0'; + mush_strncpy(n, atr_value(a), BUFFER_LEN); return n; } @@ -722,8 +802,7 @@ shortalias(dbref it) return n; } - strncpy(n, s, BUFFER_LEN - 1); - n[BUFFER_LEN - 1] = '\0'; + mush_strncpy(n, s, BUFFER_LEN); if ((s = strchr(n, ';'))) *s = '\0'; @@ -741,8 +820,8 @@ shortname(dbref it) static char n[BUFFER_LEN]; /* STATIC */ char *s; - strncpy(n, Name(it), BUFFER_LEN - 1); - n[BUFFER_LEN - 1] = '\0'; + mush_strncpy(n, Name(it), BUFFER_LEN); + if (IsExit(it)) { if ((s = strchr(n, ';'))) *s = '\0'; diff --git a/src/version.c b/src/version.c index b8979f0..8923ea3 100644 --- a/src/version.c +++ b/src/version.c @@ -20,19 +20,20 @@ #endif #include "confmagic.h" -void do_version _((dbref player)); +void do_version(dbref player); void do_version(player) dbref player; { - char buff[BUFFER_LEN]; + char *buff; notify_format(player, T("You are connected to %s"), MUDNAME); - strcpy(buff, ctime(&globals.start_time)); - buff[strlen(buff) - 1] = '\0'; /* eat the newline */ + buff = mush_strdup(ctime(&globals.start_time), "VERSION.TIME"); + notify_format(player, T("Last restarted: %s"), buff); + mush_free(buff, "VERSION.TIME"); notify_format(player, "CobraMUSH v%s [%s]", VERSION, VBRANCH); #ifdef WIN32 diff --git a/src/wait.c b/src/wait.c new file mode 100644 index 0000000..ce22d76 --- /dev/null +++ b/src/wait.c @@ -0,0 +1,190 @@ +/** + * \file wait.c + * + * \brief Process and process-group control functions. + */ + +#include "config.h" +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef I_FCNTL +#include +#endif +#ifdef I_SYS_TYPES +#include +#endif +#ifdef HAVE_SYS_TIME_H +#include +#endif +#ifdef HAVE_SYS_RESOURCE_H +#include +#endif +#include +#include +#include +#include "wait.h" + +void penn_perror(const char *); + +/** Portable wait + * \param child pid of specific child proccess to wait for. Only meaningful if HAVE_WAITPID is defined. + * \param status pointer to store the child process's exit status in. + * \param flags optional flags to pass to waitpid() or wait3(). + * \return pid of child process that exited, or -1. + */ +pid_t +mush_wait(pid_t child __attribute__ ((__unused__)), + WAIT_TYPE *status __attribute__ ((__unused__)), + int flags __attribute__ ((__unused__))) +{ + +#if defined(HAVE_WAITPID) + return waitpid(child, status, flags); +#elif defined(HAVE_WAIT3) + return wait3(status, flags, NULL); +#elif defined(HAVE_WAIT) + /* Wait as long as it's okay to block */ + if (flags == 0) + return wait(status); + else + return -1; +#else + /* Not implemented */ + return -1; +#endif +} + +/** Portable setpgid()/setpgrp() + * \param pid process to change group. 0 for current process. + * \param pgrp new process group. + * \return 0 on success, -1 on failure. + */ +int +set_process_group(pid_t pid __attribute__ ((__unused__)), + pid_t pgrp __attribute__ ((__unused__))) +{ +#if defined(HAVE_SETPGID) + + return setpgid(pid, pgrp); + +#elif defined(HAVE_SETPGRP) + +#ifndef VOID_SETPGRP + return setpgrp(pid, pgrp); +#else + return setpgrp(); +#endif + +#else + return 0; +#endif +} + +/** Create a new process group if possible. + * Equivalent to set_process_group(0, getpid()). + * \return 0 on success, -1 on failure + */ +int +new_process_group(void) +{ + return set_process_group(0, getpid()); +} + +/** Create a new process session if possible. + * See documentation for setsid(2). If that system call + * is not available, make a new process group. + * \return 0 on success, -1 on failure + */ +int +new_process_session(void) +{ +#if defined(HAVE_SETSID) + return setsid(); +#else + /* Close enough for government work */ + return new_process_group(); +#endif +} + + +/** + * Lowers the scheduling priority of a process by a given amount. Note that + * on Unix, the higher the number, the lower the priority. + * \param pid the process id of the process to change. + * \param prio how much to add to the priority. + * \return 0 on success, -1 on error. + */ +int +lower_priority_by(pid_t pid, int prio) +{ + int newprio = 0; +#ifdef HAVE_GETPRIORITY + errno = 0; + if ((newprio = getpriority(PRIO_PROCESS, pid)) < 0) { + if (errno != 0) + return -1; + } +#endif + newprio += prio; + + if (newprio > 20) + newprio = 20; + +#ifdef HAVE_SET_PRIORITY + return setpriority(PRIO_PROCESS, pid, newprio); +#else + return 0; +#endif +} + +/* This stuff is here because info_slave and netmud both use it + and I don't want to duplicate code, and putting it anywhere else + will draw it too much stuff into info_slave */ + +static int +lock_fp(FILE * f, bool what) +{ +#ifdef HAVE_FCNTL + struct flock lock; + int ret; + + memset(&lock, 0, sizeof lock); + lock.l_whence = SEEK_SET; + lock.l_start = 0; + lock.l_len = 0; + + if (what) + lock.l_type = F_WRLCK; + else + lock.l_type = F_UNLCK; + + ret = fcntl(fileno(f), F_SETLKW, &lock); + if (ret < 0) + perror("fcntl"); + + return ret; +#else + return -1; +#endif +} + +/** Obtain an exclusive advisory lock on a file pointer. Can block. + * \param f the file to lock + * \return 0 on success, -1 on failure. + */ +int +lock_file(FILE * f) +{ + return lock_fp(f, 1); +} + +/** Release a lock on a file pointer. + * \param f the file to lock + * \return 0 on success, -1 on failure. + */ +int +unlock_file(FILE * f) +{ + return lock_fp(f, 0); +} diff --git a/src/warnings.c b/src/warnings.c index 4906b72..eb41063 100644 --- a/src/warnings.c +++ b/src/warnings.c @@ -280,7 +280,7 @@ void do_warnings(dbref player, const char *name, const char *warns) { dbref thing; - warn_type w; + warn_type w, old; switch (thing = match_result(player, name, NOTYPE, MAT_EVERYTHING)) { case NOTHING: @@ -301,8 +301,9 @@ do_warnings(dbref player, const char *name, const char *warns) break; } + old = Warnings(thing); w = parse_warnings(player, warns); - if (w >= 0) { + if (w != old) { Warnings(thing) = w; if (Warnings(thing)) notify_format(player, T("@warnings set to: %s"), @@ -399,6 +400,7 @@ unparse_warnings(warn_type warns) warns &= ~the_flag; } } + *tp = '\0'; return tbuf1; } diff --git a/src/wild.c b/src/wild.c index 48a0569..c34713d 100644 --- a/src/wild.c +++ b/src/wild.c @@ -33,7 +33,7 @@ #include "ansi.h" #include "mymalloc.h" #include "parse.h" -#include "pcre.h" +#include "mypcre.h" #include "confmagic.h" /** Force a char to be lowercase */ @@ -47,13 +47,13 @@ const unsigned char *tables = NULL; /** Pointer to character tables */ -static int wild1 - (const char *RESTRICT tstr, const char *RESTRICT dstr, int arg, - char **wbuf, int *len, int cs, char **ary, int max); -static int wild(const char *RESTRICT s, const char *RESTRICT d, int p, int cs, - char **ary, int max, char *buffer, int len); -static int check_literals(const char *RESTRICT tstr, const char *RESTRICT dstr, - int cs); +static bool wild1 + (const char *restrict tstr, const char *restrict dstr, int arg, + char **wbuf, ssize_t * len, bool cs, char **ary, size_t max); +static bool wild(const char *restrict s, const char *restrict d, int p, bool cs, + char **ary, size_t max, char *buffer, ssize_t len); +static bool check_literals(const char *restrict tstr, const char *restrict dstr, + bool cs); static char *strip_backslashes(const char *str); /** Do a wildcard match, without remembering the wild data. @@ -65,11 +65,11 @@ static char *strip_backslashes(const char *str); * \retval 1 dstr matches the tstr pattern. * \retval 0 dstr does not match the tstr pattern. */ -int -quick_wild(const char *RESTRICT tstr, const char *RESTRICT dstr) +bool +quick_wild(const char *restrict tstr, const char *restrict dstr) { - /* quick_wild_new does the real work, but before we call it, - * we do some sanity checking. + /* quick_wild_new does the real work, but before we call it, + * we do some sanity checking. */ if (!check_literals(tstr, dstr, 0)) return 0; @@ -86,8 +86,8 @@ quick_wild(const char *RESTRICT tstr, const char *RESTRICT dstr) * \retval 1 dstr matches the tstr pattern. * \retval 0 dstr does not match the tstr pattern. */ -int -quick_wild_new(const char *RESTRICT tstr, const char *RESTRICT dstr, int cs) +bool +quick_wild_new(const char *restrict tstr, const char *restrict dstr, bool cs) { while (*tstr != '*') { switch (*tstr) { @@ -164,8 +164,8 @@ quick_wild_new(const char *RESTRICT tstr, const char *RESTRICT dstr, int cs) * \retval 1 dstr matches the tstr pattern. * \retval 0 dstr does not match the tstr pattern. */ -int -atr_wild(const char *RESTRICT tstr, const char *RESTRICT dstr) +bool +atr_wild(const char *restrict tstr, const char *restrict dstr) { int starcount; @@ -245,8 +245,12 @@ atr_wild(const char *RESTRICT tstr, const char *RESTRICT dstr) /* Scan for possible matches. */ while (*dstr) { - if (EQUAL(0, *dstr, *tstr) && atr_wild(tstr + 1, dstr + 1)) - return 1; + if (EQUAL(0, *dstr, *tstr)) { + if (!*(tstr + 1) && *(dstr + 1)) + return 0; /* No more in pattern string, but more in target */ + if (atr_wild(tstr + 1, dstr + 1)) + return 1; + } if (starcount < 2 && *dstr == '`') return 0; dstr++; @@ -261,12 +265,12 @@ atr_wild(const char *RESTRICT tstr, const char *RESTRICT dstr) * DO NOT CALL THIS FUNCTION DIRECTLY - DOING SO MAY RESULT IN * SERVER CRASHES AND IMPROPER ARGUMENT RETURN. * - * Side Effect: this routine modifies the 'global_eval_context.wnxt' global variable, + * Side Effect: this routine modifies the 'wnxt' global variable, * and what it points to. */ -static int -wild1(const char *RESTRICT tstr, const char *RESTRICT dstr, int arg, - char **wbuf, int *len, int cs, char **ary, int max) +static bool +wild1(const char *restrict tstr, const char *restrict dstr, int arg, + char **wbuf, ssize_t * len, bool cs, char **ary, size_t max) { const char *datapos; int argpos, numextra; @@ -313,7 +317,7 @@ wild1(const char *RESTRICT tstr, const char *RESTRICT dstr, int arg, /* If at end of pattern, slurp the rest, and leave. */ if (!tstr[1]) { - int tlen; + ssize_t tlen; tlen = strlen(dstr); if (tlen < *len) { ary[arg] = *wbuf; @@ -399,7 +403,7 @@ wild1(const char *RESTRICT tstr, const char *RESTRICT dstr, int arg, * First do the '*'... */ { - int datalen; + ssize_t datalen; datalen = (dstr - datapos) - numextra; if (datalen + 1 <= *len) { ary[argpos++] = *wbuf; @@ -407,7 +411,7 @@ wild1(const char *RESTRICT tstr, const char *RESTRICT dstr, int arg, *wbuf += datalen; *(*wbuf)++ = '\0'; *len -= datalen + 1; - datapos = dstr - numextra; + datapos = dstr - numextra; } } @@ -420,8 +424,8 @@ wild1(const char *RESTRICT tstr, const char *RESTRICT dstr, int arg, *(*wbuf)++ = *datapos++; *(*wbuf)++ = '\0'; *len -= 2; - numextra--; - } + numextra--; + } } /* It's done! */ @@ -435,11 +439,11 @@ wild1(const char *RESTRICT tstr, const char *RESTRICT dstr, int arg, * * This function may crash if malloc() fails. * - * Side Effect: this routine modifies the 'global_eval_context.wnxt' global variable. + * Side Effect: this routine modifies the 'wnxt' global variable. */ -static int -wild(const char *RESTRICT s, const char *RESTRICT d, int p, int cs, - char **ary, int max, char *buffer, int len) +static bool +wild(const char *restrict s, const char *restrict d, int p, bool cs, + char **ary, size_t max, char *buffer, ssize_t len) { /* Do fast match to see if pattern matches. If yes, do it again, remembering this time.. */ @@ -462,16 +466,16 @@ wild(const char *RESTRICT s, const char *RESTRICT d, int p, int cs, return wild1(s, d, p, &buffer, &len, cs, ary, max); } - /** Wildcard match, possibly case-sensitive, and remember the wild data - * in matches, storing them in data. + * in matches, using the data buffer to store them. + * * This routine will cause crashes if fed NULLs instead of strings. * * \param s pattern to match against. * \param d string to check. * \param cs if 1, case-sensitive; if 0, case-insensitive. - * \param ary An array to store the grabs in - * \param max Number of elements ary can hold + * \param matches An array to store the grabs in + * \param nmatches Number of elements ary can hold * \param data Buffer used to hold the matches. The elements of ary * are set to pointers into this buffer. * \param len The number of bytes in data. Twice the length of d should @@ -479,11 +483,11 @@ wild(const char *RESTRICT s, const char *RESTRICT d, int p, int cs, * \retval 1 d matches s. * \retval 0 d doesn't match s. */ -int -wild_match_case_r(const char *RESTRICT s, const char *RESTRICT d, int cs, - char **matches, int nmatches, char *data, int len) +bool +wild_match_case_r(const char *restrict s, const char *restrict d, bool cs, + char **matches, size_t nmatches, char *data, ssize_t len) { - int n; + size_t n; for (n = 0; n < nmatches; n++) matches[n] = NULL; @@ -506,12 +510,13 @@ wild_match_case_r(const char *RESTRICT s, const char *RESTRICT d, int cs, * \retval 1 d matches s * \retval 0 d doesn't match s */ -int -regexp_match_case_r(const char *RESTRICT s, const char *RESTRICT val, int cs, - char **matches, int nmatches, char *data, int len) +bool +regexp_match_case_r(const char *restrict s, const char *restrict val, bool cs, + char **matches, size_t nmatches, char *data, ssize_t len) { pcre *re; - int i; + pcre_extra *extra; + size_t i; const char *errptr; const char *d; size_t delenn; @@ -533,11 +538,12 @@ regexp_match_case_r(const char *RESTRICT s, const char *RESTRICT val, int cs, } add_check("pcre"); d = remove_markup(val, &delenn); - /* + extra = default_match_limit(); + /* * Now we try to match the pattern. The relevant fields will * automatically be filled in by this. */ - if ((subpatterns = pcre_exec(re, NULL, d, delenn - 1, 0, 0, offsets, 99)) + if ((subpatterns = pcre_exec(re, extra, d, delenn - 1, 0, 0, offsets, 99)) < 0) { mush_free(re, "pcre"); return 0; @@ -555,9 +561,9 @@ regexp_match_case_r(const char *RESTRICT s, const char *RESTRICT val, int cs, * with other languages. */ - for (i = 0; i < nmatches && i < subpatterns && len > 1; i++) { - int sublen; - + for (i = 0; i < nmatches && (int) i < subpatterns && (size_t) len > i; i++) { + ssize_t sublen; + sublen = pcre_copy_substring(d, offsets, subpatterns, (int) i, data, len); if (sublen < 0) @@ -583,10 +589,11 @@ regexp_match_case_r(const char *RESTRICT s, const char *RESTRICT val, int cs, * \retval 1 d matches s. * \retval 0 d doesn't match s. */ -int -quick_regexp_match(const char *RESTRICT s, const char *RESTRICT d, int cs) +bool +quick_regexp_match(const char *restrict s, const char *restrict d, bool cs) { pcre *re; + pcre_extra *extra; const char *sptr; size_t slen; const char *errptr; @@ -611,17 +618,38 @@ quick_regexp_match(const char *RESTRICT s, const char *RESTRICT d, int cs) } add_check("pcre"); sptr = remove_markup(d, &slen); - /* + extra = default_match_limit(); + /* * Now we try to match the pattern. The relevant fields will * automatically be filled in by this. */ - r = pcre_exec(re, NULL, sptr, slen - 1, 0, 0, offsets, 99); + r = pcre_exec(re, extra, sptr, slen - 1, 0, 0, offsets, 99); mush_free(re, "pcre"); return r >= 0; } +/** Regexp match of a pre-compiled regexp, with no memory. + * \param re the regular expression + * \param subj the string to match against. + * \return true or false + */ +bool +qcomp_regexp_match(const pcre * re, const char *subj) +{ + int len; + int offsets[99]; + pcre_extra *extra; + + if (!re || !subj) + return false; + + len = strlen(subj); + extra = default_match_limit(); + return pcre_exec(re, extra, subj, len, 0, 0, offsets, 99) >= 0; +} + /** Either an order comparison or a wildcard match with no memory. * @@ -632,25 +660,25 @@ quick_regexp_match(const char *RESTRICT s, const char *RESTRICT d, int cs) * \retval 1 d matches s. * \retval 0 d doesn't match s. */ -int -local_wild_match_case(const char *RESTRICT s, const char *RESTRICT d, int cs) +bool +local_wild_match_case(const char *restrict s, const char *restrict d, bool cs) { if (s && *s) { - switch (*s) { - case '>': - s++; - if (is_number(s) && is_number(d)) - return (parse_number(s) < parse_number(d)); - else - return (strcoll(s, d) < 0); - case '<': - s++; - if (is_number(s) && is_number(d)) - return (parse_number(s) > parse_number(d)); - else - return (strcoll(s, d) > 0); + switch (*s) { + case '>': + s++; + if (is_number(s) && is_number(d)) + return (parse_number(s) < parse_number(d)); + else + return (strcoll(s, d) < 0); + case '<': + s++; + if (is_number(s) && is_number(d)) + return (parse_number(s) > parse_number(d)); + else + return (strcoll(s, d) > 0); default: - return quick_wild_new(s, d, cs); + return quick_wild_new(s, d, cs); } } else return (!d || !*d) ? 1 : 0; @@ -662,7 +690,7 @@ local_wild_match_case(const char *RESTRICT s, const char *RESTRICT d, int cs) * \retval 1 s contains a * or ? * \retval 0 s does not contain a * or ? */ -int +bool wildcard(const char *s) { if (strchr(s, '*') || strchr(s, '?')) @@ -670,8 +698,8 @@ wildcard(const char *s) return 0; } -static int -check_literals(const char *RESTRICT tstr, const char *RESTRICT dstr, int cs) +static bool +check_literals(const char *restrict tstr, const char *restrict dstr, bool cs) { /* Every literal string in tstr must appear, in order, in dstr, * or no match can happen. That is, tstr is the pattern and dstr diff --git a/src/wiz.c b/src/wiz.c index 267225c..cec3587 100644 --- a/src/wiz.c +++ b/src/wiz.c @@ -16,6 +16,9 @@ #include #ifdef I_SYS_TIME #include +#ifdef TIME_WITH_SYS_TIME +#include +#endif #else #include #endif @@ -77,6 +80,7 @@ struct search_spec { 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. */ }; int tport_dest_ok(dbref player, dbref victim, dbref dest); @@ -473,11 +477,12 @@ do_teleport(dbref player, const char *arg1, const char *arg2, int silent, if (IsPlayer(destination) && Can_Locate(player,destination) && Tel_Where(player, destination) && IsPlayer(victim) && !inside) { if (!silent && loc != Location(destination)) - did_it(victim, victim, NULL, NULL, "OXTPORT", NULL, NULL, loc); + did_it_with(victim, victim, NULL, NULL, "OXTPORT", NULL, NULL, loc, + player, NOTHING, NA_INTER_HEAR); safe_tel(victim, Location(destination), silent); if (!silent && loc != Location(destination)) - did_it(victim, victim, "TPORT", NULL, "OTPORT", NULL, "ATPORT", - Location(destination)); + did_it_with(victim, victim, "TPORT", NULL, "OTPORT", NULL, "ATPORT", + Location(destination), player, loc, NA_INTER_HEAR); return; } /* check needed for NOTHING. Especially important for unlinked exits */ @@ -561,11 +566,12 @@ do_teleport(dbref player, const char *arg1, const char *arg2, int silent, (destination == Owner(victim)) || (!Fixed(Owner(victim)) && !Fixed(player)))) { if (!silent && loc != destination) - did_it(victim, victim, NULL, NULL, "OXTPORT", NULL, NULL, loc); + did_it_with(victim, victim, NULL, NULL, "OXTPORT", NULL, NULL, loc, + player, NOTHING, NA_INTER_HEAR); safe_tel(victim, destination, silent); if (!silent && loc != destination) - did_it(victim, victim, "TPORT", NULL, "OTPORT", NULL, "ATPORT", - destination); + did_it_with(victim, victim, "TPORT", NULL, "OTPORT", NULL, "ATPORT", + destination, player, loc, NA_INTER_HEAR); if ((victim != player) && !(Puppet(victim) && (Owner(victim) == Owner(player)))) { if (!Quiet(player) && !(Quiet(victim) && (Owner(victim) == player))) @@ -610,7 +616,7 @@ do_force(dbref player, const char *what, char *command) int j; if ((victim = match_controlled(player, what)) == NOTHING) { - notify(player, "Sorry."); + notify(player, T("Sorry.")); return; } if (options.log_forces) { @@ -1056,7 +1062,6 @@ do_kick(dbref player, const char *num) void do_debug_examine(dbref player, const char *name) { - MAIL *mp; dbref thing; if (!Admin(player)) { @@ -1077,10 +1082,7 @@ do_debug_examine(dbref player, const char *name) switch (Typeof(thing)) { case TYPE_PLAYER: -#ifdef USE_MAILER - mp = desc_mail(thing); - notify_format(player, T("First mail sender: %d"), mp ? mp->from : NOTHING); -#endif + break; case TYPE_THING: notify_format(player, "Location: %d", Location(thing)); notify_format(player, "Home: %d", Home(thing)); @@ -1176,11 +1178,11 @@ do_search(dbref player, const char *arg1, char **arg3) int nthings = 0, nexits = 0, nrooms = 0, nplayers = 0, ndivisions = 0; dbref *things, *exits, *rooms, *players, *divisions; - things = (dbref *) mush_malloc(sizeof(dbref) * nresults, "dbref_list"); - exits = (dbref *) mush_malloc(sizeof(dbref) * nresults, "dbref_list"); - rooms = (dbref *) mush_malloc(sizeof(dbref) * nresults, "dbref_list"); - players = (dbref *) mush_malloc(sizeof(dbref) * nresults, "dbref_list"); - divisions = (dbref *) mush_malloc(sizeof(dbref) * nresults, "dbref_list"); + things = mush_calloc(nresults, sizeof(dbref), "dbref_list"); + exits = mush_calloc(nresults, sizeof(dbref), "dbref_list"); + rooms = mush_calloc(nresults, sizeof(dbref), "dbref_list"); + players = mush_calloc(nresults, sizeof(dbref), "dbref_list"); + divisions = mush_calloc(nresults, sizeof(dbref), "dbref_list"); for (n = 0; n < nresults; n++) { switch (Typeof(results[n])) { @@ -1206,10 +1208,11 @@ do_search(dbref player, const char *arg1, char **arg3) } if (nrooms) { - notify(player, "\nROOMS:"); + notify(player, T("\nROOMS:")); for (n = 0; n < nrooms; n++) { tbp = tbuf; - safe_format(tbuf, &tbp, "%s [owner: ", object_header(player, rooms[n])); + safe_format(tbuf, &tbp, T("%s [owner: "), + object_header(player, rooms[n])); safe_str(object_header(player, Owner(rooms[n])), tbuf, &tbp); safe_chr(']', tbuf, &tbp); *tbp = '\0'; @@ -1220,7 +1223,7 @@ do_search(dbref player, const char *arg1, char **arg3) if (nexits) { dbref from, to; - notify(player, "\nEXITS:"); + notify(player, T("\nEXITS:")); for (n = 0; n < nexits; n++) { tbp = tbuf; if (Source(exits[n]) == NOTHING) @@ -1228,11 +1231,12 @@ do_search(dbref player, const char *arg1, char **arg3) else from = Source(exits[n]); to = Destination(exits[n]); - safe_format(tbuf, &tbp, "%s [from ", object_header(player, exits[n])); - safe_str((from == NOTHING) ? "NOWHERE" : object_header(player, from), + safe_format(tbuf, &tbp, T("%s [from "), + object_header(player, exits[n])); + safe_str((from == NOTHING) ? T("NOWHERE") : object_header(player, from), tbuf, &tbp); - safe_str(" to ", tbuf, &tbp); - safe_str((to == NOTHING) ? "NOWHERE" : object_header(player, to), + safe_str(T(" to "), tbuf, &tbp); + safe_str((to == NOTHING) ? T("NOWHERE") : object_header(player, to), tbuf, &tbp); safe_chr(']', tbuf, &tbp); *tbp = '\0'; @@ -1241,10 +1245,10 @@ do_search(dbref player, const char *arg1, char **arg3) } if (nthings) { - notify(player, "\nTHINGS:"); + notify(player, T("\nTHINGS:")); for (n = 0; n < nthings; n++) { tbp = tbuf; - safe_format(tbuf, &tbp, "%s [owner: ", + safe_format(tbuf, &tbp, T("%s [owner: "), object_header(player, things[n])); safe_str(object_header(player, Owner(things[n])), tbuf, &tbp); safe_chr(']', tbuf, &tbp); @@ -1254,7 +1258,7 @@ do_search(dbref player, const char *arg1, char **arg3) } if (nplayers) { - notify(player, "\nPLAYERS:"); + notify(player, T("\nPLAYERS:")); for (n = 0; n < nplayers; n++) { tbp = tbuf; safe_str(object_header(player, players[n]), tbuf, &tbp); @@ -1285,11 +1289,11 @@ do_search(dbref player, const char *arg1, char **arg3) T ("Totals: Rooms...%d Exits...%d Things...%d Players...%d Divisions...%d"), nrooms, nexits, nthings, nplayers, ndivisions); - mush_free((Malloc_t) rooms, "dbref_list"); - mush_free((Malloc_t) exits, "dbref_list"); - mush_free((Malloc_t) things, "dbref_list"); - mush_free((Malloc_t) players, "dbref_list"); - mush_free((Malloc_t) divisions, "dbref_list"); + mush_free(rooms, "dbref_list"); + mush_free(exits, "dbref_list"); + mush_free(things, "dbref_list"); + mush_free(players, "dbref_list"); + mush_free(divisions, "dbref_list"); } if (results) mush_free(results, "search_results"); @@ -1435,7 +1439,7 @@ do_sitelock(dbref player, const char *site, const char *opts, const char *who, { if (opts && *opts) { - int can, cant; + uint32_t can, cant; dbref whod = AMBIGUOUS; /* Options form of the command. */ if (!site || !*site) { @@ -1455,20 +1459,23 @@ do_sitelock(dbref player, const char *site, const char *opts, const char *who, } } - add_access_sitelock(player, site, whod, can, cant); - write_access_file(); - if (whod != AMBIGUOUS) { - notify_format(player, - T("Site %s access options for %s(%s) set to %s"), - site, Name(whod), unparse_dbref(whod), opts); - do_log(LT_WIZ, player, NOTHING, - T("*** SITELOCK *** %s for %s(%s) --> %s"), site, - Name(whod), unparse_dbref(whod), opts); - } else { - notify_format(player, T("Site %s access options set to %s"), site, opts); - do_log(LT_WIZ, player, NOTHING, "*** SITELOCK *** %s --> %s", site, opts); + if (add_access_sitelock(player, site, whod, can, cant)) { + write_access_file(); + if (whod != AMBIGUOUS) { + notify_format(player, + T("Site %s access options for %s(%s) set to %s"), + site, Name(whod), unparse_dbref(whod), opts); + do_log(LT_WIZ, player, NOTHING, + T("*** SITELOCK *** %s for %s(%s) --> %s"), site, + Name(whod), unparse_dbref(whod), opts); + } else { + notify_format(player, T("Site %s access options set to %s"), site, + opts); + do_log(LT_WIZ, player, NOTHING, "*** SITELOCK *** %s --> %s", site, + opts); + } + return; } - return; } else { /* Backward-compatible non-options form of the command, * or @sitelock/name @@ -1479,16 +1486,18 @@ do_sitelock(dbref player, const char *site, const char *opts, const char *who, do_list_access(player); return; case SITELOCK_ADD: - add_access_sitelock(player, site, AMBIGUOUS, 0, ACS_CREATE); - write_access_file(); - notify_format(player, T("Site %s locked"), site); - do_log(LT_WIZ, player, NOTHING, "*** SITELOCK *** %s", site); + if (add_access_sitelock(player, site, AMBIGUOUS, 0, ACS_CREATE)) { + write_access_file(); + notify_format(player, T("Site %s locked"), site); + do_log(LT_WIZ, player, NOTHING, "*** SITELOCK *** %s", site); + } break; case SITELOCK_BAN: - add_access_sitelock(player, site, AMBIGUOUS, 0, ACS_DEFAULT); - write_access_file(); - notify_format(player, T("Site %s banned"), site); - do_log(LT_WIZ, player, NOTHING, "*** SITELOCK *** %s", site); + if (add_access_sitelock(player, site, AMBIGUOUS, 0, ACS_DEFAULT)) { + write_access_file(); + notify_format(player, T("Site %s banned"), site); + do_log(LT_WIZ, player, NOTHING, "*** SITELOCK *** %s", site); + } break; case SITELOCK_CHECK:{ struct access *ap; @@ -1743,6 +1752,7 @@ fill_search_spec(dbref player, const char *owner, int nargs, const char **args, spec->high = db_top - 1; spec->start = 1; /* 1-indexed */ spec->count = 0; + spec->lock = TRUE_BOOLEXP; /* set limits on who we search */ if (!owner || !*owner || strcasecmp(owner, "all") == 0) @@ -1925,6 +1935,8 @@ fill_search_spec(dbref player, const char *owner, int nargs, const char **args, notify(player, T("Unknown division.")); 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) || @@ -1978,7 +1990,7 @@ fill_search_spec(dbref player, const char *owner, int nargs, const char **args, /* Does the actual searching */ static int raw_search(dbref player, const char *owner, int nargs, const char **args, - dbref **result, PE_Info * pe_info) + dbref **result, PE_Info *pe_info) { size_t result_size; size_t nresults = 0; @@ -1995,20 +2007,25 @@ raw_search(dbref player, const char *owner, int nargs, const char **args, 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; } - if ((spec.owner != ANY_OWNER && spec.owner != Owner(player) - && !(CanSearch(player, spec.owner) || (spec.type == TYPE_PLAYER)) || - (ZMaster(spec.owner) && eval_lock(player, spec.owner, Zone_Lock)))) { + if ((spec.owner != ANY_OWNER && + spec.owner != Owner(player) && + (!(CanSearch(player, spec.owner) || (spec.type == TYPE_PLAYER)) + || (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; } result_size = (db_top / 4) + 1; *result = - (dbref *) mush_malloc(sizeof(dbref) * result_size, "search_results"); + (dbref *) mush_calloc(result_size, sizeof(dbref), "search_results"); if (!*result) mush_panic(T("Couldn't allocate memory in search!")); @@ -2046,6 +2063,8 @@ raw_search(dbref player, const char *owner, int nargs, const char **args, if (i < (8 * DP_BYTES)) continue; } + if(spec.lock != TRUE_BOOLEXP && !eval_boolexp(n, spec.lock, player, NULL)) + continue; if (*spec.eval) { char *ebuf1; const char *ebuf2; @@ -2075,8 +2094,7 @@ raw_search(dbref player, const char *owner, int nargs, const char **args, if (nresults >= result_size) { dbref *newresults; result_size *= 2; - newresults = - (dbref *) realloc((Malloc_t) *result, sizeof(dbref) * result_size); + newresults = (dbref *) realloc(*result, sizeof(dbref) * result_size); if (!newresults) mush_panic(T("Couldn't reallocate memory in search!")); *result = newresults; @@ -2085,5 +2103,7 @@ raw_search(dbref player, const char *owner, int nargs, const char **args, (*result)[nresults++] = (dbref) n; } + if (spec.lock != TRUE_BOOLEXP) + free_boolexp(spec.lock); return (int) nresults; } diff --git a/test/MUSHConnection.pm b/test/MUSHConnection.pm new file mode 100644 index 0000000..39c362d --- /dev/null +++ b/test/MUSHConnection.pm @@ -0,0 +1,158 @@ +package MUSHConnection; + +# use strict; +use IO::Poll; +use IO::Socket::INET; + +my $nextpat = "PATTERN000000001"; + +sub new { + my $proto = shift; + my $class = ref($proto) || $proto; + my $self = []; + $self->[0] = IO::Socket::INET->new(); + $self->[1] = {}; + $self->[1]->{PREFIX} = '=-=-= OUTPUTPREFIX =-=-='; + $self->[1]->{SUFFIX} = '=-=-= OUTPUTSUFFIX =-=-='; + $self->[1]->{MATCHER} = {}; + bless($self, $class); + $self->connect(@_) if @_; + return $self; +} + +sub connected { + my $self = shift; + + my $socket = $self->[0]; + return $socket->connected(); +} + +sub connect { + my $self = shift; + my $addr = shift; + my $port = shift; + my $name = shift; + my $passwd = shift; + + + my $socket = $self->[0]; + $socket->close if $socket->connected(); + $self->[0] = IO::Socket::INET->new(PeerAddr => $addr, PeerPort => $port, + Proto => "tcp"); + $socket = $self->[0]; +# $socket->connect(PeerAddr => $addr, PeerPort => $port, Proto => "tcp"); + $socket->autoflush(1); + $socket->timeout(30); + + $self->read_to_pattern('.') || return; + $self->read_to_empty(); + $socket->print("connect $name $passwd\r\n"); + $socket->flush(); + $self->read_to_pattern('.') || return; + $self->read_to_empty(); + sleep(1); + $socket->print("OUTPUTPREFIX " . $self->[1]->{PREFIX} . "\r\n"); + $socket->print("OUTPUTSUFFIX " . $self->[1]->{SUFFIX} . "\r\n"); + $socket->print("say CodeMUSH $$\r\n"); + $self->read_to_pattern("CodeMUSH $$") || return; +} + +sub disconnect { + my $self = shift; + + my $socket = $self->[0]; + $socket->close if $socket->connected(); +} + +sub read_to_pattern { + my $self = shift; + my $pattern = shift; + +# warn "Looking for pattern $pattern\n"; + my $matcher = $self->[1]->{MATCHER}->{$pattern}; + unless ($matcher) { + my $patsub = $pattern; +# $patsub =~ s/(\W)/\\$1/go; + my $sub = <[1]->{MATCHER}->{$pattern} = $matcher; + } +# warn "Using matcher $matcher\n"; + + my $socket = $self->[0]; + my $buffer = $self->[1]->{BUFFER}; + my @match = &$matcher($buffer); + my $poll = new IO::Poll; + $poll->mask($socket => POLLIN | POLLERR | POLLHUP); + until (@match > 1) { +# warn "Looping...\n"; + my $buf; + my $amount = $socket->sysread($buf, 1024); +# warn "Read $amount: $buf...\n"; + $amount || ($self->disconnect(), return); + $buffer .= $buf; + } continue { + @match = &$matcher($buffer); + } + $self->[1]->{BUFFER} = $match[2]; + +# warn "Found match: ".join(",", @match)."\n"; +# warn "Returning: ".join(",",@match[0,1])."\n"; + return (@match[0,1]); +} + +sub read_to_empty { + my $self = shift; + +# warn "Emptying input...\n"; + my $socket = $self->[0]; + my $poll = new IO::Poll; + $poll->mask($socket => POLLIN | POLLERR | POLLHUP); + my $result = $self->[1]->{BUFFER}; + my $buf; + while ($poll->poll(0) && !($poll->events($socket) & POLLERR | POLLHUP)) { + $socket->read($buf, 1024, 0); + $result .= $buf; + } + $self->[1]->{BUFFER} = ""; +# warn "Have result: $result\n"; + return $result; +} + +sub command { + my $self = shift; + my $command = shift; + my $socket = $self->[0]; + my $noise = $self->read_to_empty(); + $socket->print($command."\r\n"); + my @result = $self->read_to_pattern($self->[1]->{PREFIX}); + $noise .= $result[0]; + $self->[1]->{NOISE} = $noise; + @result = $self->read_to_pattern($self->[1]->{SUFFIX}); + $result[0] =~ s/^[\r\n]+//o; +# warn "Noise: $noise\n"; + return $result[0]; +} + +sub noise { + my $self = shift; + return $self->[1]->{NOISE}; +} + +sub listen { + my $self = shift; + $self->command("think Listening!"); + $self->[1]->{NOISE} =~ s/^\r?\n//o; +# warn "LISTENING!: ".$self->[1]->{NOISE}."\n"; + return $self->[1]->{NOISE}; +} + +1; diff --git a/test/PennMUSH.pm b/test/PennMUSH.pm new file mode 100644 index 0000000..8bf8e29 --- /dev/null +++ b/test/PennMUSH.pm @@ -0,0 +1,113 @@ +package PennMUSH; + +use File::Copy; +use File::Path; +use MUSHConnection; + +my @pids = (); + +sub new { + my $proto = shift; + my $class = ref($proto) || $proto; + my $self = {}; + bless($self, $class); + if (@_) { + $self->{HOST} = shift; + $self->{PORT} = shift; + $self->{VALGRIND} = shift; + $self->start(@_); + } else { + $self->start(); + } + + return $self; +} + +sub start { + my $self = shift; + srand(); + $self->{HOST} = "localhost" unless defined $self->{HOST}; + if (!exists $self->{PORT} || $self->{PORT} <= 0) { + $self->{PORT} = int(rand(2000)) + 12000; + } + my $port = $self->{PORT}; + rmtree("testgame"); + mkpath(["testgame/data", "testgame/log", "testgame/txt"]); + copyConfig("../game/mushcnf.dst", "testgame/test.cnf", + "port" => $port, + "compress_program" => "", + "uncompress_program" => "", + "compress_suffix" => "", + @_); + copy("../game/alias.cnf", "testgame/alias.cnf"); + copy("../game/names.cnf", "testgame/names.cnf"); + copy("../game/restrict.cnf", "testgame/restrict.cnf"); + my $file; + foreach $file (glob("../game/txt/*.txt")) { + my $target = $file; + $target =~ s-../game-testgame-o; + copy($file, $target); + } + symlink("../../src/netmud", "testgame/netmush"); + symlink("../../src/info_slave", "testgame/info_slave"); + my $child = fork(); + if ($child > 0) { + my $j; + my $line; + push(@pids, $child); + $self->{PID} = $child; + foreach $j (1..20) { + next unless open(LOG, "testgame/log/netmush.log"); + while ($line = ) { + close(LOG), return $port if $line =~ /^Listening on port $port /; + } + } continue { + sleep(1); + } + die "Could not start game process properly; pid $child!\n"; + } elsif (defined($child)) { + chdir("testgame"); + my @execargs = ("./netmush", "--no-session", "test.cnf"); + unshift @execargs, "valgrind", '--log-file=../valgrind-%p.log' + if $self->{VALGRIND}; + exec @execargs; + } else { + die "Could not spawn game process!\n"; + } +} + +sub copyConfig { + my $from = shift; + my $to = shift; + my %subs = @_; + + open(FROM, "<$from") || die "Could not open template configuration.\n"; + open(TO, ">$to") || die "Could not write test configuration.\n"; + my $line; + while ($line = ) { + next if $line =~ /^\s*#/o; + next unless $line =~ /^\s*(\w+)\s/o; + my $key = $1; + $line = $key . " " . $subs{$key} . "\n" if defined($subs{$key}); + } continue { + print TO $line; + } + close(TO); + close(FROM); +} + +sub login { + my $self = shift; + return MUSHConnection->new($self->{HOST}, $self->{PORT}, @_); +} + +sub loginGod { + my $self = shift; + return MUSHConnection->new($self->{HOST}, $self->{PORT}, "One", "one"); +} + +END { + kill("TERM", @pids); +} + +1; diff --git a/test/README b/test/README new file mode 100644 index 0000000..08c1867 --- /dev/null +++ b/test/README @@ -0,0 +1,22 @@ +Regression tests for Penn functions and commands. + +Usage: + perl runtest.pl testFOO.pl ... + +or + ./alltests.sh + +The test*.pl files are frameworks for tests, not actual perl scripts. + +Their format: + + login mortal + expect N failures! + run tests: + perl code + +All the lines above the 'run tests:' one are optional. + +Look at existing files for how to write tests. Some hints: $god is +always available as a test connection. If 'login mortal' was given, +$mortal is too. diff --git a/test/TestHarness.pm b/test/TestHarness.pm new file mode 100644 index 0000000..e585a32 --- /dev/null +++ b/test/TestHarness.pm @@ -0,0 +1,170 @@ +package TestHarness; +use strict; +use vars qw/%tests $testcount @failures $alltests $allfailures $allexpected/; +use vars qw/$testfiles $use_mortal/; +use subs qw/test summary/; + +$alltests = 0; +$allfailures = 0; +$allexpected = 0; +$testfiles = 0; +$use_mortal = 0; + +sub new { + my $class = shift; + my $script = shift; + my %self = ( + -expected => 0, + -depends => [], + -test => undef, + ); +# print "Looking at $script\n"; + $script =~ /^test(.*)\.pl$/o; + my $name = $1; + $self{-name} = $name; + warn "Duplicate test $name\n" if exists $tests{$name}; + my $code = 'sub { my $god = shift; ' . "\n"; + open IN, "<", $script or die "Couldn't open ${script}: $!\n"; + while () { + chomp; + next if /^\s*(?:#|$)/o; + last if /^run tests:$/o; + if (/^depends on (.*)$/o) { + push @{$self{-depends}}, $1; + } + if (/^expect (\d+) failures!$/) { + $self{-expected} = $1; + print "Expecting $1 failures in $name\n"; + } + if (/^\s*login mortal$/) { + $code .= 'my $mortal = shift;' . "\n"; + $use_mortal = 1; + } + } + while () { + $code .= $_; + } + close IN; + $code .= "}"; +# print "Test function for $name:\n$code\n"; + $self{-test} = eval $code; + my $obj = bless \%self; + $tests{$name} = $obj; + return $obj; +} + +sub run { + my $self = shift; + my $god = shift; + my $mortal = shift; + my ($failures, $test) = (0,0); + + foreach my $dep (@{$self->{-depends}}) { + my $test = $tests{$dep}; + if (defined $test) { + $test->run($god, $mortal); + } else { + warn "Unresolved dependency $dep\n"; + } + } + + local ($testcount, @failures) = (0, ()); + + my $name = $self->{-name}; + + print "Running tests for ${name}:\n"; + + &{$self->{-test}}($god, $mortal); + + $testfiles++; + $alltests += $testcount; + $allfailures += @failures; + $allexpected += $self->{-expected}; + + summary $self->{-name}, $testcount, \@failures, $self->{-expected}; +} + +END { + print "Totals:\n"; + summary("all tests run", $alltests, $allfailures, $allexpected) + if $testfiles > 1; +} + +$| = 1; + +sub test { + my $name = shift; + my $conn = shift; + my $command = shift; + my $patterns = shift; + + $patterns = [$patterns] if ref($patterns) ne "ARRAY"; + + print substr("Running $name".(" "x80), 0, 78)."\r"; + + my $result = defined($command) ? $conn->command($command) : $conn->listen(); + my $verdict = 1; + + foreach my $pattern (@$patterns) { + my $matchpattern = $pattern; + my $negate = 0; + if ($matchpattern =~ s/^!//o) { + $negate = 1; + } else { + $matchpattern =~ s/^=//o; + } + + if ($negate) { + $verdict = 0 if $result =~ /$matchpattern/; + } else { + $verdict = 0 unless $result =~ /$matchpattern/; + } + } + + $testcount++; + unless ($verdict) { + push(@failures, $name); + print "TEST FAILURE: $name\n"; + if (defined($command)) { + print " command: $command\n"; + } else { + print " listening\n"; + } + chomp $result; + if ($result =~ /\n/o) { + print " result:\n$result\n"; + } else { + print " result: $result\n"; + } + foreach my $pattern (@$patterns) { + print " pattern: $pattern\n"; + } + print "\n"; + } +} + +sub summary { + my ($name, $testcount, $failures, $expected) = @_; + print ":"x70, "\n"; + print "\n"; + my $fcount = 0; + if (ref $failures) { + $fcount = scalar @$failures; + } else { + $fcount = $failures; + } + my $scount = $testcount - $fcount; + print "$testcount tests, $scount succeeded, $fcount failed ($expected expected failures)\n"; + if ($fcount != $expected) { + print "failed tests:\n"; + my $str = join(", ", @$failures); + while (length($str) > 67) { + $str =~ s/^(.{1,67}), //o; + print " $1,\n"; + } + print " $str\n"; + } + print "\n"; +} + +1; diff --git a/test/alltests.sh b/test/alltests.sh new file mode 100755 index 0000000..7fc4638 --- /dev/null +++ b/test/alltests.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +exec /usr/bin/perl runtest.pl $@ test*.pl + diff --git a/test/alltests.sh.in b/test/alltests.sh.in new file mode 100644 index 0000000..b08850c --- /dev/null +++ b/test/alltests.sh.in @@ -0,0 +1,4 @@ +#!/bin/sh + +exec @PERL@ runtest.pl $@ test*.pl + diff --git a/test/runtest.pl b/test/runtest.pl new file mode 100644 index 0000000..e2af01a --- /dev/null +++ b/test/runtest.pl @@ -0,0 +1,26 @@ +#!/usr/bin/perl -w +use strict; +use Getopt::Long; +use PennMUSH; +use TestHarness; + +my ($valgrind, $host, $port) = (0,"localhost",0); +GetOptions "valgrind" => \$valgrind, + "host" => \$host, + "port" => \$port; + +my $mush = PennMUSH->new($host, $port, $valgrind); + +my @tests = map { TestHarness->new($_); } @ARGV; + +my $god = $mush->loginGod; + +my $mortal = undef; +if ($TestHarness::use_mortal) { + $god->command('@pcreate Mortal=mortal'); + $mortal = $mush->login("Mortal", "mortal"); +} + +foreach my $test (@tests) { + $test->run($god, $mortal); +} diff --git a/test/testalias.pl b/test/testalias.pl new file mode 100644 index 0000000..2ca459d --- /dev/null +++ b/test/testalias.pl @@ -0,0 +1,13 @@ +run tests: +test('alias.1', $god, '@name me=God', ['Name set.']); +test('alias.2', $god, '@name me=One', ['Name set.']); +test('alias.3', $god, '@alias me=God', ['Alias set.']); +test('alias.4', $god, '@name me=God', ['Name set.']); +test('alias.5', $god, '@alias me=God', ['Alias set.']); +test('alias.6', $god, '@name me=One', ['Name set.']); +test('alias.7', $god, '@name me=God', ['Name set.']); +test('alias.8', $god, '@alias me=God;One', ['Alias set.']); +test('alias.9', $god, '@name me=Love', ['Name set.']); +test('alias.10', $god, '@alias me', ['Alias removed.']); +test('alias.11', $god, '@name me=God', ['Name set.']); + diff --git a/test/testatree.pl b/test/testatree.pl new file mode 100644 index 0000000..8d0e0b8 --- /dev/null +++ b/test/testatree.pl @@ -0,0 +1,251 @@ +login mortal +run tests: +# First, the basic tests enforcing tree-nature of the attributes. +# Attrs may not start or end in ` +test("atree.basic.1", $god, "&foo` me=baz", "not a very good name"); +test("atree.basic.2", $god, "&`bar me=baz", "not a very good name"); +# Not even if there's a preexisting branch +test("atree.basic.3", $god, "&foo me=baz", "Set"); +test("atree.basic.4", $god, "&foo` me=baz", "not a very good name"); +# You may not have two ` in a row +test("atree.basic.5", $god, "&foo``bar me=baz", "not a very good name"); +# Make a small tree +test("atree.basic.6", $god, "&foo me=baz", "Set"); +test("atree.basic.7", $god, "&foo`bar me=baz", "Set"); +test("atree.basic.8", $god, "&foo`bar`baz me=baz", "Set"); +# Cannot clear branches with leaves until the leaves are cleared +test("atree.basic.9", $god, "&foo me", "!Cleared"); +test("atree.basic.10", $god, "&foo`bar me", "!Cleared"); +test("atree.basic.11", $god, "&foo`bar`baz me", "Cleared"); +test("atree.basic.12", $god, "&foo`bar me", "Cleared"); +test("atree.basic.13", $god, "&foo me", "Cleared"); +# You can wipe, though. +test("atree.basic.14", $god, "&foo me=baz", "Set"); +test("atree.basic.15", $god, "&foo`bar me=baz", "Set"); +test("atree.basic.16", $god, "&foo`bar`baz me=baz", "Set"); +test("atree.basic.17", $god, '@wipe me/foo', "wiped"); + +# Branch permissions +# May make a leaf without supporting branch +test("atree.branch.1", $god, "&foo`bar me=baz", "!You must set FOO first"); +# And it must make the branch +test("atree.branch.2", $god, "think hasattr(me, foo)", "1"); +# Another child should not wipe the previous values +test("atree.branch.3", $god, "&foo`bar`baz me=baz", "!You must set FOO first"); +test("atree.branch.4", $god, "think get(me/foo`bar)", "baz"); +# Clean up again +test("atree.branch.5", $god, '@wipe me/foo', "wiped"); + +# Wildcard attribute matching +# Rebuild a tree +test("atree.matching.1", $god, "&foo me=baz", "Set"); +test("atree.matching.2", $god, "&foo`bar me=baz", "Set"); +test("atree.matching.3", $god, "&foo`baz me=baz", "Set"); +test("atree.matching.4", $god, "&foo`bar`baz me=baz", "Set"); +# Examine should show a ` attribute flag for foo, foo`bar, but not foo`bar`baz +test("atree.matching.5", $god, "examine me/foo", 'FOO \[.*`\]'); +test("atree.matching.6", $god, "examine me/foo`bar", 'FOO`BAR \[.*`\]'); +test("atree.matching.7", $god, "examine me/foo`bar`baz", 'FOO`BAR`BAZ \[[^`]*\]'); +# Examine doesn't show recursively, by default +test("atree.matching.8", $god, "examine me", ['FOO \[.*`\]', '!FOO`BAR']); +# But it will if you ask for it +test("atree.matching.9", $god, "examine me/**", + ['FOO \[.*`\]', 'FOO`BAR \[', 'FOO`BAR`BAZ \[[^`]+\]']); +# If you ask for an attribute, you don't get its children +test('atree.matching.10', $god, 'examine me/FOO', + ['FOO \[.*`\]', '!FOO`BAR \[', '!FOO`BAR`BAZ \[[^`]+\]']); +# You have to ask for the children +test('atree.matching.11', $god, 'examine me/FOO`', + ['!FOO \[.*`\]', 'FOO`BAR \[', 'FOO`BAZ \[', '!FOO`BAR`BAZ \[[^`]+\]']); +test('atree.matching.12', $god, 'examine me/FOO`BAR`', + ['!FOO \[.*`\]', '!FOO`BAR \[', '!FOO`BAZ \[', 'FOO`BAR`BAZ \[[^`]+\]']); +test('atree.matching.13', $god, 'examine me/FOO`*', + ['!FOO \[.*`\]', 'FOO`BAR \[', 'FOO`BAZ \[', '!FOO`BAR`BAZ \[[^`]+\]']); +# A single * doesn't match ` +test('atree.matching.14', $god, 'examine me/FOO*Z', + ['!FOO \[.*`\]', '!FOO`BAR \[', '!FOO`BAZ \[', '!FOO`BAR`BAZ \[[^`]+\]']); +# A double * does match ` +test('atree.matching.15', $god, 'examine me/FOO**Z', + ['!FOO \[.*`\]', '!FOO`BAR \[', 'FOO`BAZ \[', 'FOO`BAR`BAZ \[[^`]+\]']); +# @decompile gets everything by default +test('atree.matching.16', $god, '@decompile me', + ['&FOO ', '&FOO`BAR ', '&FOO`BAR`BAZ ']); +# But only the top layer if you say so +test('atree.matching.17', $god, '@decompile me/*', + ['&FOO ', '!&FOO`BAR ', '!&FOO`BAR`BAZ ']); +# lattr() works like examine, only top by default +test('atree.matching.18', $god, 'think lattr(me)', + ['\bFOO\b', '!\bFOO`BAR\b', '!\bFOO`BAR`BAZ\b']); +test('atree.matching.19', $god, 'think lattr(me/**)', + ['\bFOO\b', '\bFOO`BAR\b', '\bFOO`BAR`BAZ\b']); +test("atree.matching.20", $god, 'think flags(me/foo)', '`'); + +# Permissions checks +# Need a mortal for this... +# Build a tree from different places... +test('atree.perms.2', $god, '&foo mortal=baz', 'Set'); +test('atree.perms.3', $god, '&foo`bar mortal=baz', 'Set'); +test('atree.perms.4', $mortal, '@decompile me', ['&FOO ', '&FOO`BAR ']); +test('atree.perms.5', $mortal, '&foo`bar me=baz', 'Set'); +test('atree.perms.6', $mortal, '&foo`bar`baz me=baz', 'Set'); +# Start flipping perms... +test('atree.perms.7', $god, '@set mortal/foo`bar=wiz', 'set'); +test('atree.perms.8', $mortal, '@decompile me', + ['&FOO ', '&FOO`BAR ', '&FOO`BAR`BAZ ']); +# Cannot overwrite wiz-only as mortal, or make stuff under it +test('atree.perms.9', $mortal, '&foo`bar me=baz', '!Set'); +test('atree.perms.10', $mortal, '&foo`bar`baz me=baz', '!Set'); +test('atree.perms.11', $mortal, '&foo`bar`qux me=baz', '!Set'); +# Cannot see under mortal_dark as mortal +test('atree.perms.12', $god, '@set mortal/foo`bar=mortal_dark', 'set'); +test('atree.perms.13', $mortal, '@decompile me', + ['&FOO ', '!&FOO`BAR ', '!&FOO`BAR`BAZ ', '!&FOO`BAR`QUX ']); +# Still can't write there (still wiz-only) +test('atree.perms.14', $mortal, '&foo`bar me=baz', '!Set'); +test('atree.perms.15', $mortal, '&foo`bar`baz me=baz', '!Set'); +test('atree.perms.16', $mortal, '&foo`bar`qux me=baz', '!Set'); +# Turn off wiz-only, but still can't see it... +test('atree.perms.17', $god, '@set mortal/foo`bar=!wiz', 'reset'); +test('atree.perms.18', $mortal, '@decompile me', + ['&FOO ', '!&FOO`BAR ', '!&FOO`BAR`BAZ ', '!&FOO`BAR`QUX ']); +# But you can write there again... +test('atree.perms.19', $mortal, '&foo`bar me=baz', 'Set'); +test('atree.perms.20', $mortal, '&foo`bar`baz me=baz', 'Set'); +test('atree.perms.21', $mortal, '&foo`bar`qux me=baz', 'Set'); + +# Parenting and ancestry +test('atree.parent.1', $mortal, '@create ancestor', 'Created'); +test('atree.parent.2', $mortal, '@create parent', 'Created'); +test('atree.parent.3', $mortal, '@create child', 'Created'); +test('atree.parent.4', $mortal, 'drop child', '.'); +test('atree.parent.5', $mortal, 'drop parent', '.'); +test('atree.parent.6', $mortal, 'drop ancestor', '.'); +test('atree.parent.7', $mortal, '@parent child=parent', 'Parent changed'); +test('atree.parent.8', $god, + '@config/set ancestor_thing=[after(num(ancestor),#)]', 'set'); +# Can we see stuff from the ancestor? +test('atree.parent.9', $mortal, '&foo ancestor=urk', 'Set'); +test('atree.parent.10', $mortal, '&foo`bar ancestor=urk', 'Set'); +test('atree.parent.11', $mortal, '&foo`bar`baz ancestor=urk', 'Set'); +test('atree.parent.12', $mortal, 'think get(child/foo)', 'urk'); +test('atree.parent.13', $mortal, 'think get(child/foo`bar)', 'urk'); +# Can we see stuff from the parent? +test('atree.parent.14', $mortal, '&foo parent=wibble', 'Set'); +test('atree.parent.15', $mortal, '&foo`bar parent=gleep', 'Set'); +test('atree.parent.16', $mortal, 'think get(child/foo)', 'wibble'); +test('atree.parent.17', $mortal, 'think get(child/foo`bar)', 'gleep'); +test('atree.parent.18', $mortal, '&foo`bar`baz child=boom', 'Set'); +test('atree.parent.19', $mortal, 'think -[get(child/foo)]-', '--'); +test('atree.parent.20', $mortal, 'think -[get(child/foo`bar)]-', '--'); +test('atree.parent.21', $mortal, '@wipe child/foo', 'wiped'); +# Setting no_inherit puts it back to the ancestor +test('atree.parent.22', $mortal, '@set parent/foo=no_inherit', 'set'); +test('atree.parent.23', $mortal, 'think get(child/foo)', '!wibble'); +test('atree.parent.24', $god, 'think get(child/foo`bar)', '!gleep'); +test('atree.parent.25', $god, 'think get(child/foo)', 'urk'); +test('atree.parent.26', $god, 'think get(child/foo`bar)', 'urk'); + +# Mix permissions and parents +# If parent is inheritable again, and mortal_dark, +# then we can't see the ancestor through it +test('atree.parentperms.1', $mortal, '@set parent/foo=!no_inherit', 'set'); +test('atree.parentperms.2', $god, '@set parent/foo`bar=mortal_dark', 'set'); +test('atree.parentperms.3', $mortal, 'think get(child/foo`bar`baz)', '!urk'); +# We can't see it, either +test('atree.parentperms.4', $mortal, 'think get(child/foo`bar)', '!gleep'); +test('atree.parentperms.5', $mortal, '@set parent/foo=no_inherit', 'set'); +# no_inherit trumps mortal_dark +test('atree.parentperms.6', $mortal, 'think get(child/foo`bar`baz)', 'urk'); +test('atree.parentperms.7', $mortal, 'think get(child/foo`bar)', 'urk'); +test('atree.parentperms.8', $god, '@set parent/foo=mortal_dark', 'set'); +test('atree.parentperms.9', $mortal, 'think get(child/foo`bar)', 'urk'); + +# Command checks +# Need explicit grandparent, because ancestors aren't checked for commands +test('atree.command.1', $mortal, '@create grand', []); +test('atree.command.2', $mortal, 'drop grand', []); +test('atree.command.3', $mortal, '@parent parent=grand', []); +test('atree.command.4', $mortal, '&bar grand=$bar:say Grand Bar', 'Set'); +test('atree.command.5', $mortal, '&bar`baz grand=$bar`baz:say Grand Baz', []); +test('atree.command.6', $mortal, '&bar parent=$bar:say Parent Bar', 'Set'); +test('atree.command.7', $mortal, '&bar`baz parent=$bar`baz:say Parent Baz', []); +test('atree.command.8', $mortal, '@set child=!no_command', 'set'); +# Do commands work from parent? +test('atree.command.9', $god, 'bar', '!Bar'); +test('atree.command.10', $god, undef, 'Parent Bar'); +test('atree.command.11', $god, 'bar`baz', []); +test('atree.command.12', $god, undef, 'Parent Baz'); +# Child should block parent +test('atree.command.13', $mortal, '&bar child=$bar:say Child!', 'Set'); +test('atree.command.14', $god, 'bar', '!Bar'); +test('atree.command.15', $god, undef, ['!Bar', 'Child']); +# Child no_command blocks parent branch, too +test('atree.command.16', $mortal, '@set child/bar=no_command', 'set'); +test('atree.command.17', $god, 'bar`baz', '!Baz'); +test('atree.command.18', $god, undef, '!Baz'); +# Parent no_command not masked by child not no_command... +test('atree.command.19', $mortal, '@set child/bar=!no_command', 'set'); +test('atree.command.20', $mortal, '@set parent/bar=no_command', 'set'); +test('atree.command.21', $god, 'bar`baz', '!Baz'); +test('atree.command.22', $god, undef, '!Baz'); +# no_command can be on the leaf, too +test('atree.command.23', $mortal, '@set parent/bar=!no_command', 'set'); +test('atree.command.24', $mortal, '@set parent/bar`baz=no_command', 'set'); +test('atree.command.25', $god, 'bar`baz', '!Baz'); +test('atree.command.26', $god, undef, '!Baz'); +# no_inherit trumps no_command +test('atree.command.27', $mortal, '@set parent/bar=no_inherit', 'set'); +test('atree.command.28', $mortal, '@set parent/bar`baz=no_command', 'set'); +test('atree.command.29', $god, 'bar`baz', '!Baz'); +test('atree.command.30', $god, undef, 'Grand Baz'); +test('atree.command.31', $mortal, '@set parent/bar=no_command', 'set'); +test('atree.command.32', $mortal, '&bar child', []); +test('atree.command.33', $god, 'bar', '!Baz'); +test('atree.command.34', $god, undef, 'Grand Bar'); + +# Test for the child recognition bugs: +test('atree.sortorder.1', $mortal, '&abc grand=$abc:say Grand ABC', 'Set'); +test('atree.sortorder.2', $mortal, '&abcd grand=$abcd:say Grand D', 'Set'); +test('atree.sortorder.3', $mortal, '&abc`xyz grand=$abc`xyz:say Grand XYZ', []); +test('atree.sortorder.4', $mortal, '&abc parent=$abc:say Parent ABC', 'Set'); +test('atree.sortorder.5', $mortal, '&abcd parent=$abcd:say Parent D', 'Set'); +test('atree.sortorder.6', $mortal, '&abc`xyz parent=$abc`xyz:say Parent XYZ', []); +test("atree.sortorder.7", $god, 'examine parent', 'ABC \[.*`\]'); +test("atree.sortorder.8", $god, '&abc parent', '!Cleared'); +test('atree.sortorder.9', $mortal, '@set child=!no_command', 'set'); +# Do commands work from parent? +test('atree.sortorder.10', $god, 'abc', '!ABC'); +test('atree.sortorder.11', $god, undef, 'Parent ABC'); +test('atree.sortorder.12', $god, 'abc`xyz', []); +test('atree.sortorder.13', $god, undef, 'Parent XYZ'); +# Child should block parent +test('atree.sortorder.14', $mortal, '&abc child=$abc:say Child!', 'Set'); +test('atree.sortorder.15', $god, 'abc', '!ABC'); +test('atree.sortorder.16', $god, undef, ['!ABC', 'Child']); +# Child no_command blocks parent branch, too +test('atree.sortorder.17', $mortal, '@set child/abc=no_command', 'set'); +test('atree.sortorder.18', $god, 'abc`xyz', '!XYZ'); +test('atree.sortorder.19', $god, undef, '!XYZ'); +# Parent no_command not masked by child not no_command... +test('atree.sortorder.20', $mortal, '@set child/abc=!no_command', 'set'); +test('atree.sortorder.21', $mortal, '@set parent/abc=no_command', 'set'); +test('atree.sortorder.22', $god, 'abc`xyz', '!XYZ'); +test('atree.sortorder.23', $god, undef, '!XYZ'); +# no_command can be on the leaf, too +test('atree.sortorder.24', $mortal, '@set parent/abc=!no_command', 'set'); +test('atree.sortorder.25', $mortal, '@set parent/abc`xyz=no_command', 'set'); +test('atree.sortorder.26', $god, 'abc`xyz', '!XYZ'); +test('atree.sortorder.27', $god, undef, '!XYZ'); +# no_inherit trumps no_command +test('atree.sortorder.28', $mortal, '@set parent/abc=no_inherit', 'set'); +test('atree.sortorder.29', $mortal, '@set parent/abc`xyz=no_command', 'set'); +test('atree.sortorder.30', $god, 'abc`xyz', '!XYZ'); +test('atree.sortorder.31', $god, undef, 'Grand XYZ'); +test('atree.sortorder.32', $mortal, '@set parent/abc=no_command', 'set'); +test('atree.sortorder.33', $mortal, '&abc child', []); +test('atree.sortorder.34', $god, 'abc', '!XYZ'); +test('atree.sortorder.35', $god, undef, 'Grand ABC'); +# wipe check +test("atree.sortorder.36", $god, '@wipe parent', 'wiped'); +test("atree.sortorder.37", $god, '@wipe grand/abc', []); +test("atree.sortorder.38", $god, 'examine grand/**', '!ABC\b'); diff --git a/test/testdecompose.pl b/test/testdecompose.pl new file mode 100644 index 0000000..50b085a --- /dev/null +++ b/test/testdecompose.pl @@ -0,0 +1,7 @@ +login mortal +run test: +test('decompose.1', $mortal, 'think decompose([ansi(hr,b[ansi(f,la)]h)])', '\[ansi\(hr,b(\)\])?\[ansi\((?(1)fhr|f),la\)\](?(1)\[ansi\(hr,h|h)\)\]'); +test('decompose.2', $mortal, 'think decompose(a\ \ \ \ b)', 'a %b %bb'); +test('decompose.3', $mortal, 'think decompose(s(tab%treturn%r))', 'tab%treturn%r'); +test('decompose.4', $mortal, 'think decompose(before(ansi(h,x),x)hello)', 'hello'); +test('decompose.5', $mortal, 'think decompose([before(ansi(h,blah),\[)])', '\[ansi\(h,blah\)\]'); diff --git a/test/testdigest.pl b/test/testdigest.pl new file mode 100644 index 0000000..3b9b16c --- /dev/null +++ b/test/testdigest.pl @@ -0,0 +1,13 @@ +login mortal +run tests: +test('digest.1', $mortal, 'think digest(md2,foo)', 'd11f8ce29210b4b50c5e67533b699d02'); +test('digest.2', $mortal, 'think digest(md5,foo)', 'acbd18db4cc2f85cedef654fccc4a4d8'); +test('digest.3', $mortal, 'think digest(sha,foo)', '752678a483e77799a3651face01d064f9ca86779'); +test('digest.4', $mortal, 'think digest(sha1,foo)', '0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33'); +test('digest.5', $mortal, 'think digest(dss1,foo)', '0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33'); +test('digest.6', $mortal, 'think digest(ripemd160,foo)', '42cfa211018ea492fdee45ac637b7972a0ad6873'); +test('digest.7', $mortal, 'think digest(md4,foo)', '0ac6700c491d70fb8650940b1ca1e4b2'); + + +test('base64.1', $mortal, 'think encode64(test string)', 'dGVzdCBzdHJpbmc='); +test("base64.2", $mortal, "think decode64(encode64(this is another fine mess you've gotten us into))", "this is another fine mess you've gotten us into"); diff --git a/test/testdistxd.pl b/test/testdistxd.pl new file mode 100644 index 0000000..8c560db --- /dev/null +++ b/test/testdistxd.pl @@ -0,0 +1,10 @@ +run tests: +test('dist2d.1', $god, 'think dist2d(0,0, 5,5)', "7.071068"); +test('dist2d.2', $god, 'think lmath(dist2d, 0 0 5 5)', "7.071068"); +test('dist2d.3', $god, 'think dist2d(0,0, 0,0)', "0"); +test('dist2d.4', $god, 'think dist2d(0,0, 0,1)', "1"); + +test('dist3d.1', $god, 'think dist3d(0,0,0, 5,5,5)', "8\\.660254"); +test('dist3d.2', $god, 'think lmath(dist3d, 0 0 0 5 5 5)', "8\\.660254"); +test('dist3d.3', $god, 'think dist3d(0,0,0, 0,0,0)', "0"); +test('dist3d.4', $god, 'think dist3d(0,0,0, 1,0,0)', "1"); diff --git a/test/testfirstof.pl b/test/testfirstof.pl new file mode 100644 index 0000000..3795dbc --- /dev/null +++ b/test/testfirstof.pl @@ -0,0 +1,13 @@ +run tests: +test('firstof.1', $god, 'think firstof(0,0,2)', '2'); +test('firstof.2', $god, 'think firstof(2,0,0)', '2'); +test('firstof.3', $god, 'think firstof(0,0,0)', '0'); +test('firstof.4', $god, 'think firstof(1,2,3)', '1'); +test('firstof.5', $god, 'think allof(0,0,2,)', '2'); +test('firstof.6', $god, 'think allof(2,0,0,)', '2'); +test('firstof.7', $god, 'think allof(0,0,0,)', ''); +test('firstof.8', $god, 'think allof(1,2,3,)', '1 2 3'); +test('firstof.9', $god, 'think allof(0,0,2,|)', '2'); +test('firstof.10', $god, 'think allof(2,0,0,|)', '2'); +test('firstof.11', $god, 'think allof(0,0,0,|)', ''); +test('firstof.12', $god, 'think allof(1,2,3,|)', '1|2|3'); diff --git a/test/testgrep.pl b/test/testgrep.pl new file mode 100644 index 0000000..dff3b35 --- /dev/null +++ b/test/testgrep.pl @@ -0,0 +1,37 @@ +login mortal +run tests: +$mortal->command("&FIRST me=first"); +$mortal->command("&SECOND me=second"); +$mortal->command("&THIRD me=third"); + +test('grep.1', $mortal, 'think grep(me,*,d)', 'SECOND THIRD'); +test('grep.2', $mortal, 'think grep(me,S*,d)', 'SECOND'); +test('grep.3', $mortal, 'think grep(me,*,*d*)', '!SECOND THIRD'); +test('grep.4', $mortal, 'think grep(me,*,D)', '!SECOND THIRD'); + +test('grep.5', $mortal, 'think wildgrep(me,*,*d*)', 'SECOND THIRD'); +test('grep.6', $mortal, 'think wildgrep(me,*,d)', '!SECOND THIRD'); +test('grep.7', $mortal, 'think wildgrep(me,*,first)', 'FIRST'); +test('grep.8', $mortal, 'think wildgrep(me,*,FIRST)', '!FIRST'); + +test('grep.9', $mortal, 'think regrep(me,*,*d*)', '!SECOND THIRD'); +test('grep.10', $mortal, 'think regrep(me,*,d)', 'SECOND THIRD'); +test('grep.11', $mortal, 'think regrep(me,*,d$)', 'SECOND THIRD'); +test('grep.12', $mortal, 'think regrep(me,*,first)', 'FIRST'); +test('grep.13', $mortal, 'think regrep(me,*,FIRST)', '!FIRST'); + +test('grep.14', $mortal, 'think grepi(me,*,d)', 'SECOND THIRD'); +test('grep.15', $mortal, 'think grepi(me,S*,d)', 'SECOND'); +test('grep.16', $mortal, 'think grepi(me,*,*d*)', '!SECOND THIRD'); +test('grep.17', $mortal, 'think grepi(me,*,D)', 'SECOND THIRD'); + +test('grep.18', $mortal, 'think wildgrepi(me,*,*d*)', 'SECOND THIRD'); +test('grep.19', $mortal, 'think wildgrepi(me,*,d)', '!SECOND THIRD'); +test('grep.20', $mortal, 'think wildgrepi(me,*,first)', 'FIRST'); +test('grep.21', $mortal, 'think wildgrepi(me,*,FIRST)', 'FIRST'); + +test('grep.22', $mortal, 'think regrepi(me,*,*d*)', '!SECOND THIRD'); +test('grep.23', $mortal, 'think regrepi(me,*,d)', 'SECOND THIRD'); +test('grep.24', $mortal, 'think regrepi(me,*,d$)', 'SECOND THIRD'); +test('grep.25', $mortal, 'think regrepi(me,*,first)', 'FIRST'); +test('grep.26', $mortal, 'think regrepi(me,*,FIRST)', 'FIRST'); diff --git a/test/testhastype.pl b/test/testhastype.pl new file mode 100644 index 0000000..1b14e46 --- /dev/null +++ b/test/testhastype.pl @@ -0,0 +1,12 @@ +expect 2 failures! +run tests: +test('hastype.1', $god, 'think hastype(#0, room)', ['1', '!#-1']); +test('hastype.2', $god, 'think hastype(#1, player)', ['1', '!#-1']); +test('hastype.3', $god, '@create foo', []); +test('hastype.4', $god, 'think hastype(foo, thing)', ['1', '!#-1']); +test('hastype.5', $god, '@rec foo', []); +test('hastype.6', $god, '@rec foo', []); +test('hastype.7', $god, 'think hastype(#3, garbage)', ['1', '!#-1']); +test('hastype.8', $god, '@open foo', []); +test('hastype.9', $god, 'think hastype(#3, exit)', ['1', '!#-1']); + diff --git a/test/testinsert.pl b/test/testinsert.pl new file mode 100644 index 0000000..fe20d04 --- /dev/null +++ b/test/testinsert.pl @@ -0,0 +1,21 @@ +use PennMUSH; +use MUSHConnection; +use TestHarness; + +$mush = PennMUSH->new(); +$god = $mush->loginGod(); + +test('insert.1', $god, 'think insert(a b c,0,X)', 'a b c'); +test('insert.2', $god, 'think insert(a b c,1,X)', 'X a b c'); +test('insert.3', $god, 'think insert(a b c,2,X)', 'a X b c'); +test('insert.4', $god, 'think insert(a b c,3,X)', 'a b X c'); +test('insert.5', $god, 'think insert(a b c,4,X)', 'a b c'); +test('insert.6', $god, 'think insert(a b c,-1,X)', 'a b c X'); +test('insert.7', $god, 'think insert(a b c,-2,X)', 'a b X c'); +test('insert.8', $god, 'think insert(a b c,-3,X)', 'a X b c'); +test('insert.9', $god, 'think insert(a b c,-4,X)', 'a b c'); +test('insert.10', $god, 'think insert(a|b|c,0,|)', 'a|b|c'); +test('insert.11', $god, 'think insert(a|b|c,1,|)', 'X|a|b|c'); +test('insert.12', $god, 'think insert(a|b|c,-1,|)', 'a|b|c|X'); +test('insert.13', $god, 'think insert(a|b|c,2,|)', 'a|X|b|c'); +test('insert.14', $god, 'think insert(a|b|c,-2,|)', 'a|b|X|c'); diff --git a/test/testjust.pl b/test/testjust.pl new file mode 100644 index 0000000..74ac597 --- /dev/null +++ b/test/testjust.pl @@ -0,0 +1,20 @@ +run tests: +$god->command('@config/set tiny_math=no'); +test('ljust.1', $god, "think ljust(foo, 3)", 'foo'); +test('ljust.2', $god, "think ljust(foo, 5)X", '^foo X'); +test('ljust.3', $god, "think ljust(foo, 5, =)", '^foo=='); +test('ljust.4', $god, "think ljust(foo, 2)", '^foo'); +test('ljust.5', $god, "think ljust(foo, -3)", '^#-1 ARGUMENT MUST BE POSITIVE INTEGER'); + +test('rjust.1', $god, "think rjust(foo, 3)", 'foo'); +test('rjust.2', $god, "think rjust(foo, 5)", '^ foo'); +test('rjust.3', $god, "think rjust(foo, 5, =)", '^==foo'); +test('rjust.4', $god, "think rjust(foo, 2)", '^foo'); +test('rjust.5', $god, "think rjust(foo, -3)", '^#-1 ARGUMENT MUST BE POSITIVE INTEGER'); + +test('center.1', $god, "think center(foo, 3)", 'foo'); +test('center.2', $god, "think #[center(fo, 3)]#", '^#fo #'); +test('center.3', $god, "think center(foo, 5)X", '^ foo X'); +test('center.4', $god, "think center(foo, 5, =)", '^=foo='); +test('center.5', $god, "think center(foo, 2)", '^foo'); +test('center.6', $god, "think center(foo, -3)", '^#-1 ARGUMENT MUST BE POSITIVE INTEGER'); diff --git a/test/testletq.pl b/test/testletq.pl new file mode 100644 index 0000000..9b0e1a5 --- /dev/null +++ b/test/testletq.pl @@ -0,0 +1,3 @@ +run tests: +test("letq.1", $god, "think setr(A, 1):[letq(A, 2, \%qA)]:\%qA", '^1:2:1'); +test("letq.2", $god, "think setr(A, 1):[letq(setr(A, 2))]:\%qA", '^1:2:2'); diff --git a/test/testmath.pl b/test/testmath.pl new file mode 100644 index 0000000..3ec2ebe --- /dev/null +++ b/test/testmath.pl @@ -0,0 +1,53 @@ +run tests: +test('abs.1', $god, 'think abs(-1)', '1'); +test('abs.2', $god, 'think abs(-1.5)', '1.5'); +test('abs.3', $god, 'think abs(1)', '1'); +test('abs.4', $god, 'think abs(0)', '0'); +test('abs.5', $god, 'think abs(-0)', '0'); +test('abs.6', $god, 'think abs(99999999999)', '99999999999'); +test('abs.7', $god, 'think abs(-99999999999)', '99999999999'); + +test('cos.1',$god, 'think cos(90,d)', '^-?0\s*$'); +test('cos.2',$god, 'think cos(pi(),r)', '^-1\s*$'); +test('cos.3',$god, 'think cos(pi())', '^-1\s*$'); + +test('acos.1',$god, 'think acos(cos(90,d),d)', '^90\s*$'); +test('acos.2',$god, 'think acos(cos(1,r))', '^1\s*$'); +test('acos.3',$god, 'think acos(cos(1,r),r)', '^1\s*$'); + +test('sin.1',$god, 'think sin(90,d)', '^1\s*$'); +test('sin.2',$god, 'think sin(pi(),r)', '^-?0\s*$'); +test('sin.3',$god, 'think sin(pi())', '^-?0\s*$'); + +test('asin.1',$god, 'think asin(sin(90,d),d)', '^90\s*$'); +test('asin.2',$god, 'think asin(sin(1,r))', '^1\s*$'); +test('asin.3',$god, 'think asin(sin(1,r),r)', '^1\s*$'); + +test('tan.1',$god, 'think tan(45,d)', '^1\s*$'); +test('tan.2',$god, 'think tan(pi(),r)', '^-?0\s*$'); +test('tan.3',$god, 'think tan(pi())', '^-?0\s*$'); + +test('atan.1',$god, 'think atan(tan(45,d),d)', '^45\s*$'); +test('atan.2',$god, 'think atan(tan(1,r))', '^1\s*$'); +test('atan.3',$god, 'think atan(tan(1,r),r)', '^1\s*$'); + +test('ctu.1',$god, 'think ctu(90,d,r)', '^1.570\d*\s*$'); +test('ctu.2',$god, 'think ctu(pi(),r,d)','^180(\.00\d*)?\s*$'); + +test('sqrt.1', $god, 'think sqrt(4)', '2'); +test('sqrt.2', $god, 'think sqrt(-1)', '#-1 IMAGINARY NUMBER'); + +test('root.1', $god, 'think root(4,2)', '2'); +test('root.2', $god, 'think root(-1,2)', '#-1 IMAGINARY NUMBER'); +test('root.3', $god, 'think root(27, 3)', '3'); +test('root.4', $god, 'think root(-27, 3)', '-3'); +$god->command('@config/set float_precision=10'); +test('root.5', $god, 'think root(125, 5)', '2.6265278044'); + +test('round.0', $god, 'think round(pi(), 0)', '3'); +test('round.1', $god, 'think round(pi(), 1)', '3.1'); +test('round.2', $god, 'think round(pi(), 2)', '3.14'); +test('round.3', $god, 'think round(pi(), 3)', '3.142'); +test('round.4', $god, 'think round(pi(), 4)', '3.1416'); +test('round.5', $god, 'think round(pi(), 5)', '3.14159'); +test('round.6', $god, 'think round(-[pi()], 3)', '-3.142'); diff --git a/test/testnull.pl b/test/testnull.pl new file mode 100644 index 0000000..7598fe8 --- /dev/null +++ b/test/testnull.pl @@ -0,0 +1,9 @@ +run test: +test('null.1', $god, 'think null()', ''); +test('null.2', $god, 'think null(a)', ''); +test('null.3', $god, 'think null(a,b,c)', ''); +test('null.4', $god, 'think null(pemit(#1,test))', 'test'); +test('null.5', $god, 'think @@()', ''); +test('null.6', $god, 'think @@(a)', ''); +test('null.7', $god, 'think @@(a,b,c)', ''); +test('null.8', $god, 'think @@(pemit(#1,test))', ''); diff --git a/test/testpage.pl b/test/testpage.pl new file mode 100644 index 0000000..bf4dc57 --- /dev/null +++ b/test/testpage.pl @@ -0,0 +1,2 @@ +run tests: +test('page.1', $god, 'page/noeval %# \= =',"I can't find"); # Former crasher diff --git a/test/testrand.pl b/test/testrand.pl new file mode 100644 index 0000000..fdeefdd --- /dev/null +++ b/test/testrand.pl @@ -0,0 +1,10 @@ +run tests: +test('rand.1', $god, 'think rand(-1)', '#-1'); +test('rand.2', $god, 'think rand(0)', '#-1'); +test('rand.3', $god, 'think rand(1)', '0'); +test('rand.4', $god, 'think rand(10)', '^\d\s*$'); +test('rand.5', $god, 'think rand(0,0)', '0'); +test('rand.6', $god, 'think rand(1,1)', '1'); +test('rand.7', $god, 'think rand(2,1)', '#-1'); +test('rand.8', $god, 'think rand(0,9)', '^\d\s*$'); + diff --git a/test/testreswitch.pl b/test/testreswitch.pl new file mode 100644 index 0000000..19ef431 --- /dev/null +++ b/test/testreswitch.pl @@ -0,0 +1,20 @@ +run tests: +test('reswitch.1', $god, 'think reswitch(test STRING,t,1,0)', '1'); +test('reswitch.2', $god, 'think reswitch(test STRING,t,1,e,2,0)', '1'); +test('reswitch.3', $god, 'think reswitch(test STRING,E,1,0)', '0'); +test('reswitch.4', $god, 'think reswitch(test STRING,.\{4\}\\\s\[A-Z\]\{6\},9,t,1,E,2,0)', '9'); + +test('reswitch.5', $god, 'think reswitchall(test STRING,t,1,0)', '1'); +test('reswitch.6', $god, 'think reswitchall(test STRING,t,1,e,2,0)', '12'); +test('reswitch.7', $god, 'think reswitchall(test STRING,E,1,0)', '0'); +test('reswitch.8', $god, 'think reswitchall(test STRING,.\{4\}\\\s\[A-Z\]\{6\},9,t,1,E,2,0)', '91'); + +test('reswitch.9', $god, 'think reswitchi(test STRING,t,1,0)', '1'); +test('reswitch.10', $god, 'think reswitchi(test STRING,t,1,e,2,0)', '1'); +test('reswitch.11', $god, 'think reswitchi(test STRING,E,1,0)', '1'); +test('reswitch.12', $god, 'think reswitchi(test STRING,.\{4\}\\\s\[A-Z\]\{6\},9,t,1,E,2,0)', '9'); + +test('reswitch.13', $god, 'think reswitchalli(test STRING,t,1,0)', '1'); +test('reswitch.14', $god, 'think reswitchalli(test STRING,t,1,e,2,0)', '12'); +test('reswitch.15', $god, 'think reswitchalli(test STRING,E,1,0)', '1'); +test('reswitch.16', $god, 'think reswitchalli(test STRING,.\{4\}\\\s\[A-Z\]\{6\},9,t,1,E,2,0)', '912'); diff --git a/test/testsetfuns.pl b/test/testsetfuns.pl new file mode 100644 index 0000000..22463f9 --- /dev/null +++ b/test/testsetfuns.pl @@ -0,0 +1,7 @@ +login mortal +run tests: +test('setunion.1', $mortal, 'think setunion(,)', '^$'); +test('setunion.2', $mortal, 'think setunion( a,a)', '^a\r$'); +test('setunion.3', $mortal, 'think setunion(c a b a,a b c c)', '^a b c\r$'); +test('setunion.4', $mortal, 'think setunion(a a a,)', '^a\r$'); +test('setunion.5', $mortal, 'think setunion(,a a a)', '^a\r$'); diff --git a/test/teststringsecs.pl b/test/teststringsecs.pl new file mode 100644 index 0000000..8eb7d76 --- /dev/null +++ b/test/teststringsecs.pl @@ -0,0 +1,12 @@ +login mortal +run tests: +test('stringsecs.1', $mortal, 'think stringsecs(a)', '#-1 INVALID TIMESTRING'); +test('stringsecs.2', $mortal, 'think stringsecs(10)', '10'); +test('stringsecs.3', $mortal, 'think stringsecs(10s)', '10'); +test('stringsecs.4', $mortal, 'think stringsecs(5m)', '300'); +test('stringsecs.5', $mortal, 'think stringsecs(5m 10s)', '310'); +test('stringsecs.6', $mortal, 'think stringsecs(1h)', '3600'); +test('stringsecs.7', $mortal, 'think stringsecs(10s 5m)', '310'); +test('stringsecs.8', $mortal, 'think stringsecs(1d 2h 3m 4s)', '93784'); +test('stringsecs.9', $mortal + , 'think stringsecs(h)', '#-1 INVALID TIMESTRING'); diff --git a/test/testtr.pl b/test/testtr.pl new file mode 100644 index 0000000..c860aac --- /dev/null +++ b/test/testtr.pl @@ -0,0 +1,8 @@ +run tests: +test('tr.1', $god, 'think tr(test STRING,,)', 'test STRING'); +test('tr.2', $god, 'think tr(test STRING,t,)', '#-1'); +test('tr.3', $god, 'think tr(test STRING,,t)', '#-1'); +test('tr.4', $god, 'think tr(test STRING,t,f)', 'fesf STRING'); +test('tr.5', $god, 'think tr(test STRING,tT,fF)', 'fesf SFRING'); +test('tr.6', $god, 'think tr(test STRING,Tt,Ff)', 'fesf SFRING'); +test('tr.7', $god, 'think tr(test STRING,te,et)', 'etse STRING'); diff --git a/test/testtrim.pl b/test/testtrim.pl new file mode 100644 index 0000000..2e2f99a --- /dev/null +++ b/test/testtrim.pl @@ -0,0 +1,18 @@ +run tests: +test('trimpenn.1', $god, 'think trimpenn(XXXfooXXX, X, l)', 'fooXXX'); +test('trimpenn.2', $god, 'think trimpenn(XXXfooXXX, X, r)', 'XXXfoo'); +test('trimpenn.3', $god, 'think trimpenn(XXXfooXXX, X, b)', 'foo'); +test('trimpenn.4', $god, 'think trimpenn(XXXfooXXX, Y, l)', 'XXXfooXXX'); + +test('trimtiny.1', $god, 'think trimtiny(XXXfooXXX, L, X)', 'fooXXX'); +test('trimtiny.2', $god, 'think trimtiny(XXXfooXXX, R, X)', 'XXXfoo'); +test('trimtiny.3', $god, 'think trimtiny(XXXfooXXX, B, X)', 'foo'); +test('trimtiny.4', $god, 'think trimtiny(XXXfooXXX, l, Y)', 'XXXfooXXX'); + +$god->command('@config/set tiny_trim_fun=yes'); +test('trim.1', $god, 'think trim(XXXfooXXX, l, X)', 'fooXXX'); +$god->command('@config/set tiny_trim_fun=no'); +test('trim.2', $god, 'think trim(XXXfooXXX, X, l)', 'fooXXX'); +test('trim.3', $god, 'think @[trim(%b%bfoo%b%b)]@', 'foo'); + + diff --git a/utils/fixdepend.pl b/utils/fixdepend.pl index 83430d1..ead4be4 100644 --- a/utils/fixdepend.pl +++ b/utils/fixdepend.pl @@ -1,4 +1,5 @@ -#!/usr/local/bin/perl -pi~ -$_ = "" if m#/usr/include#; -$_ = "" if m#/usr/lib#; +#!/usr/bin/env perl -pi~ +# Get rid of all global headers. We only really care about the ones +# in hdrs/ +$_ = "" if m#:\s+/#; diff --git a/utils/gentables.c b/utils/gentables.c index 3acebcc..b6e9d39 100644 --- a/utils/gentables.c +++ b/utils/gentables.c @@ -23,7 +23,6 @@ #include #include - /* Offsets (+1) for q-register lookup. */ char q_offsets[UCHAR_MAX + 1] = { ['0'] = 1, ['1'] = 2, ['2'] = 3, ['3'] = 4, ['4'] = 5, @@ -101,34 +100,21 @@ char valid_timefmt_codes[UCHAR_MAX + 1] = { }; /* Special characters for escape() and secure() */ -char escaped_chars[UCHAR_MAX + 1] = {['%'] =1, ['\\'] = 1, - ['['] = 1, [']'] = 1, ['{'] = 1, ['}'] = 1, [';'] = 1 }; - - -char escaped_chars_s[UCHAR_MAX + 1] = { +char escaped_chars[UCHAR_MAX + 1] = { ['('] = 1, [')'] = 1, ['['] = 1, [']'] = 1, ['{'] = 1, ['}'] = 1, ['$'] = 1, ['^'] = 1, ['%'] = 1, [','] = 1, [';'] = 1, ['\\'] = 1 }; - -/* Roman Numeral Values */ -unsigned int roman_numeral_t[UCHAR_MAX + 1] = { - ['I'] = 1, - ['V'] = 5, - ['X'] = 10, - ['L'] = 50, - ['C'] = 100, - ['D'] = 500, - ['M'] = 1000, - ['i'] = 1000, - ['v'] = 5000, - ['x'] = 10000, - ['l'] = 50000, - ['c'] = 100000, - ['d'] = 500000, - ['m'] = 1000000 +/* Color codes used in ansi markup */ +char ansi_codes[UCHAR_MAX + 1] = { + ['h'] = 1, ['i'] = 1, ['f'] = 1, ['u'] = 1, ['n'] = 1, + ['x'] = 1, ['r'] = 1, ['g'] = 1, ['y'] = 1, ['b'] = 1, + ['c'] = 1, ['m'] = 1, ['w'] = 1, + ['X'] = 1, ['R'] = 1, ['G'] = 1, ['Y'] = 1, ['B'] = 1, + ['C'] = 1, ['M'] = 1, ['W'] = 1, + ['/'] = 1, ['a'] = 1 }; /** Accented characters @@ -258,19 +244,6 @@ void print_table_bool(const char *type, const char *name, fputs("};\n\n", stdout); } -void print_table_int(const char *type, const char *name, unsigned int table[], int delta) { - int n ; - printf("%s %s[%d] = {\n", type, name, UCHAR_MAX + 1); - for (n = 1; n < UCHAR_MAX + 2; n++) { - printf("%3d", table[n - 1] + delta); - if (n < UCHAR_MAX + 1) - putchar(','); - if (n % 16 == 0) - putchar('\n'); - } - fputs("};\n\n", stdout); -} - void print_entity_table(const char *name, const accent_info table[]) { int n; @@ -283,7 +256,7 @@ void print_entity_table(const char *name, if (table[n].entity) printf("{\"%s\", \"%s\"}", table[n].base, table[n].entity); else - printf("{NULL, NULL}", n); + fputs("{NULL, NULL}", stdout); if (n < UCHAR_MAX) putchar(','); putchar('\n'); @@ -297,13 +270,12 @@ int main(int argc, char *argv[]) { " * %s. Edit that file, not this one, when making changes. */\n" "#include \n\n", argv[0], __FILE__); - print_table_int("unsigned int", "roman_numeral_table", roman_numeral_t, 0); print_table_bool("signed char", "qreg_indexes", q_offsets, -1); print_table_bool("char", "active_table", parse_interesting, 0); print_table_bool("char", "atr_name_table", attribute_names, 0); print_table_bool("char", "valid_timefmt_codes", valid_timefmt_codes, 0); print_table_bool("char", "escaped_chars", escaped_chars, 0); - print_table_bool("char", "escaped_chars_s", escaped_chars_s, 0); + print_table_bool("char", "valid_ansi_codes", ansi_codes, 0); print_entity_table("accent_table", entity_table); return EXIT_SUCCESS; } diff --git a/utils/mkcmds.pl b/utils/mkcmds.pl index 7198b24..943bf90 100644 --- a/utils/mkcmds.pl +++ b/utils/mkcmds.pl @@ -14,6 +14,260 @@ use subs qw/make_patches make_switches make_cmds make_funs/; # Always present functions use subs qw/maybemove temp_header temp_source scan_files_for_pattern/; +# Main loop, dispatch for each command line argument. +foreach my $command (@ARGV) { + if ($command eq "patches") { + make_patches; + } elsif ($command eq "switches") { + make_switches; + } elsif ($command eq "commands") { + make_cmds; + } elsif ($command eq "functions") { + make_funs; + } elsif ($command eq "all") { + make_patches; + make_switches; + make_cmds; + make_funs; + } else { + warn "Unknown option '${command}'\n"; + } +} + +# Return name of a temp file in hdrs/ +sub temp_header { + return "hdrs/temp.$$.h"; +} + +# Return name of a temp file in src/ +sub temp_source { + return "src/temp.$$.c"; +} + +# maybemove(file1, file2) copies file1 to file 2 if they are different, +# otherwise just deletes file1 and leaves file2 unchanged. +sub maybemove { + my $from = shift; + my $to = shift; + + if (compare $from, $to) { + if (move $from, $to) { + print "File ${to} updated.\n"; + } else { + warn "Couldn't rename ${from} to ${to}: $!\n"; + } + } else { + print "File ${to} unchanged.\n"; + unlink $from; + } +} + +# scan_files_for_pattern(glob-pattern, re) searches all files matching +# glob-pattern for lines matching re, and returns a sorted list of +# $1's for each matching line. +sub scan_files_for_pattern { + my $filepattern = shift; + my $re = shift; + my @idents; + + foreach my $file (glob $filepattern) { + open FILE, "<", $file + or die "Cannot open ${file} for reading: $!\n"; + while () { + chomp; + push @idents, $1 if m/$re/; + } + close FILE; + } + return sort @idents; +} + + +END { + # Make sure temp files get deleted. + my @files = (temp_header(), temp_source()); + foreach my $file (@files) { + unlink $file if -f $file; + } +} + +__DATA__ + +sub make_patches { + print "Rebuilding list of installed patches\n"; + my $tempfile = temp_header; + my $patchfile = "hdrs/patches.h"; + my $auto_msg = "/* AUTOGENERATED FILE. DO NOT EDIT! */\n"; + open PATCHES, ">", $tempfile + or die "Couldn't open $tempfile for writing: $!\n"; + print PATCHES $auto_msg; + print PATCHES "#ifndef PATCHES_H\n"; + print PATCHES "#define PATCHES_H\n"; + my %patches; + if (-d "patches") { + foreach $file () { + next if $file =~ /(?:\.bak|\.orig|\.rej|~)$/o; + open FILE, "<", $file + or die "Couldn't open file '$file' for reading: $!\n"; + my $name = undef; + my $version = undef; + LINE: while () { + chomp; + $name = $1 if m/^# Patch name: (.*)/o; + $version = $1 if m/^# Patch version: (.*)/o; + if (defined $name && defined $version) { + $patches{$name} = $version; + last LINE; + } + } + close FILE; + } + if (scalar keys %patches > 0) { + print PATCHES '#define PATCHES "'; + while (my ($name, $version) = each %patches) { + print PATCHES "$name($version) "; + } + print PATCHES '"', "\n"; + } else { + print PATCHES "#undef PATCHES\n"; + } + } else { + print PATCHES "#undef PATCHES\n"; + } + print PATCHES "#endif /* PATCHES_H */\n"; + close PATCHES; + + maybemove $tempfile, $patchfile; +} + +sub make_switches { + print "Rebuilding command switch file and header.\n"; + my $auto_msg = "/* AUTOGENERATED FILE. DO NOT EDIT! */\n"; + + my $temphdr = temp_header; + my $tempsrc = temp_source; + + open CMDHDR, "<", "hdrs/command.h" or + die "Unable to open hdrs/command.h for reading: $!\n"; + my $numbytes = 20; + while () { + if (m/^#define\s+NUM_BYTES\s+(\d+)/o) { + $numbytes = $1; + last; + } + } + close CMDHDR; + + my $MAXSWITCHES = $numbytes * 8; + + my @switches = scan_files_for_pattern "src/SWITCHES", qr/^(.+)/; + + warn "Too many switches defined!\n" if length @switches > $MAXSWITCHES; + + open HDR, ">", $temphdr or + die "Unable to open $temphdr for writing: $!\n"; + open SRC, ">", $tempsrc or + die "Unable to open $tempsrc for writing: $1\n"; + + print HDR $auto_msg; + print HDR "#ifndef SWITCHES_H\n"; + print HDR "#define SWITCHES_H\n"; + + print SRC $auto_msg; + print SRC "SWITCH_VALUE switch_list[] = {\n"; + + my $n = 1; + foreach my $switch (@switches) { + print HDR "#define SWITCH_${switch} ${n}\n"; + print SRC " {\"${switch}\", SWITCH_${switch}},\n"; + $n++; + } + + print SRC " {NULL, 0}\n"; + print SRC "};\n"; + close SRC; + + print HDR "#endif /* SWITCHES_H */\n"; + close HDR; + + maybemove $temphdr, "hdrs/switches.h"; + maybemove $tempsrc, "src/switchinc.c"; +} + +# I really should combine this and make_funs into one function that does +# the work with specific files/regexps/defines passed as arguments + +sub make_cmds { + my $auto_msg = "/* AUTOGENERATED FILE. DO NOT EDIT! */\n"; + + print "Rebuilding command prototype header.\n"; + + my $tempfile = temp_header; + + my @commands = + scan_files_for_pattern "src/*.c", qr/^\s*COMMAND\(([^\)]+)\)/; + + open HDR, ">", $tempfile + or die "Can't open ${tempfile} for writing: $!\n"; + + print HDR $auto_msg; + print HDR "#ifndef CMDS_H\n"; + print HDR "#define CMDS_H\n"; + + foreach my $command (@commands) { + print HDR "COMMAND_PROTO(${command});\n"; + } + + print HDR "#endif /* CMDS_H */\n"; + close HDR; + + maybemove $tempfile, "hdrs/cmds.h"; + +} + +sub make_funs { + my $auto_msg = "/* AUTOGENERATED FILE. DO NOT EDIT! */\n"; + + print "Rebuilding function prototype header.\n"; + + my $tempfile = temp_header; + + my @functions = + scan_files_for_pattern "src/*.c", qr/^\s*FUNCTION\(([^\)]+)\)/; + + open HDR, ">", $tempfile + or die "Can't open ${tempfile} for writing: $!\n"; + + print HDR $auto_msg; + print HDR "#ifndef FUNS_H\n"; + print HDR "#define FUNS_H\n"; + + foreach my $function (@functions) { + print HDR "FUNCTION_PROTO(${function});\n"; + } + + print HDR "#endif /* FUNS_H */\n"; + close HDR; + + maybemove $tempfile, "hdrs/funs.h"; +} + +#!/usr/bin/perl -w +# perl version of the old mkcmds.sh script. Runs faster by simply not running +# a bazillion child processes. Also uses SelfLoader to avoid compiling functions +# that are never used, since it's usually invoked with at most 1 argument. +# + +use SelfLoader; +use File::Compare; +use File::Copy; +use strict; # Please ma'am may I have another? + +# SelfLoaded functions +use subs qw/make_patches make_switches make_cmds make_funs/; +# Always present functions +use subs qw/maybemove temp_header temp_source scan_files_for_pattern/; + print "Starting...\n"; # Main loop, dispatch for each command line argument. diff --git a/win32/README.mingw b/win32/README.mingw index 96dc29d..a3d9567 100644 --- a/win32/README.mingw +++ b/win32/README.mingw @@ -30,11 +30,7 @@ Last update: Saturday, 28 February 2004 6. cd pennmush then type: - ./Configure -d - - *** Note: This should configure the mush appropriately - *** if it fails to, you can attempt ./Configure - *** alone and use the mingw32 hints option when asked + ./configure 7. Now type: @@ -63,3 +59,16 @@ Last update: Saturday, 28 February 2004 /home/noltar/pennmush/game + +Raevnos has had some success cross-compiling a win32 pennmush on linux +using mingw32. Briefly: + + * Install the mingw32 cross compilation tools using your package + manager. + * Configure like so (The name of the cross-compiler might vary): + % CC=i486-mingw32-gcc ./configure --host --without-ssl --without-mysql \ + --without-sqlite3 --without-postgresql --without-pcre + * Add -lwsock32 to the LIBS= line in Makefile + * make update; make netmud + * cp src/netmud netmush.exe + * Use netmush.exe and the game/ directory on a Windows computer like usual. diff --git a/win32/confmagic.h b/win32/confmagic.h index 28859e9..8ec381c 100644 --- a/win32/confmagic.h +++ b/win32/confmagic.h @@ -6,120 +6,60 @@ * If you wish to get rid of this magic, remove this file and rerun metaconfig * without the -M option. * + * $Id: Magic_h.U,v 3.0.1.2 1993/11/10 17:32:58 ram Exp $ */ #ifndef _confmagic_h_ #define _confmagic_h_ -#ifndef HAS_BCOPY -#ifndef bcopy -#define bcopy(s,d,l) memcpy((d),(s),(l)) -#endif -#endif - -#ifndef HAS_BZERO -#ifndef bzero -#define bzero(s,l) memset((s),0,(l)) -#endif -#endif +#define inline __inline -/* If your system doesn't have the crypt(3) DES encryption code, +/* * (which isn't exportable from the U.S.), then don't encrypt */ #ifndef HAS_CRYPT #define crypt(s,t) (s) #endif -#ifdef HAS_HUGE_VAL -#define HUGE_DOUBLE HUGE_VAL -#else -#ifdef HAS_HUGE -#define HUGE_DOUBLE HUGE -#else -#ifdef HAS_MAXDOUBLE -#define HUGE_DOUBLE MAXDOUBLE -#else -#define HUGE_DOUBLE 2000000000 -#endif -#endif -#endif -#ifdef HAS_INT_MAX -#define HUGE_INT INT_MAX -#else -#ifdef HAS_MAXINT -#define HUGE_INT MAXINT -#else -#define HUGE_INT 2000000000 -#endif -#endif - -#ifndef HAS_MEMCPY -#ifndef memcpy -#define memcpy(d,s,l) bcopy((s),(d),(l)) -#endif -#endif - -#ifndef HAS_MEMMOVE -#ifndef memmove -#define memmove(d,s,l) bcopy((s),(d),(l)) -#endif -#endif - -#ifndef HAS_RANDOM -#ifndef random -#ifdef HAS_LRAND48 -#define random lrand48 -#define srandom srand48 -#else -#ifdef HAS_RAND -#define random rand -#define srandom srand -#endif -#endif -#endif -#endif +/* You better get with the 90's if this isn't true! */ +#define HAS_IEEE_MATH -#ifndef HAS_SIGCHLD +#ifndef HAVE_SIGCHLD #define SIGCHLD SIGCLD -#endif - -#ifndef HAS_SIGCLD +#elif !defined(HAVE_SIGCLD) #define SIGCLD SIGCHLD #endif -#ifndef HAS_INDEX -#ifndef index -#define index strchr -#endif -#endif - -#ifndef HAS_STRCHR -#ifndef strchr -#define strchr index -#endif +#ifndef HAVE_STRCOLL +#undef strcoll +#define strcoll strcmp #endif -#ifndef HAS_INDEX -#ifndef rindex -#define rindex strrchr +#ifndef HAVE_SNPRINTF +#ifdef HAVE__VSNPRINTF_S +#define snprintf sane_snprintf_s +/* Win32 needs size_t to be defined... */ +#include +int sane_snprintf_s(char *, size_t, const char *, ...); +#elif defined(HAVE__SNPRINTF) +#define snprintf _snprintf #endif #endif -#ifndef HAS_STRCHR -#ifndef strrchr -#define strrchr rindex +#if !defined(HAVE_VSNPRINTF) +#if defined(HAVE__VSNPRINTF_S) +#define vsnprintf(str, size, fmt, args) _vsnprintf_s((str), (size), \ + _TRUNCATE, \ + (fmt), (args)) +#elif defined(HAVE__VSNPRINTF) +#define vsnprintf _vsnprintf #endif #endif -#ifndef HAS_STRCOLL -#undef strcoll -#define strcoll strcmp -#endif - -#if !defined(WIN32) && !defined(HAS_STRXFRM) -#define strncoll strncmp -#define strncasecoll strncasecmp -#define strcasecoll strcasecmp +#if defined(HAVE_POLLTS) && !defined(HAVE_PPOLL) +/* Linux's ppoll() is identical to NetBSD's pollts() in all but name. */ +#define ppoll pollts +#define HAVE_PPOLL #endif #if defined(_MSC_VER) diff --git a/win32/patches.h b/win32/patches.h index dfe9c2d..6c841c9 100644 --- a/win32/patches.h +++ b/win32/patches.h @@ -1,4 +1,4 @@ #ifndef _PATCH_H #define _PATCH_H #undef PATCHES -#endif _PATCH_H +#endif /* _PATCH_H */ -- 2.30.2