From c0325c31e6a6d4fb34372be7abdbfab6506d520a Mon Sep 17 00:00:00 2001 From: "psyc://psyced.org/~lynX" <@> Date: Fri, 22 May 2009 00:41:07 +0200 Subject: [PATCH] merge with ldmud distribution --- CHANGELOG | 6 + mudlib/sys/debug_info.h | 6 + src/Makefile.in | 164 +-- src/actions.c | 64 +- src/array.c | 32 +- src/array.h | 97 +- src/backend.c | 23 +- src/bitstrings.c | 10 +- src/bytecode.h | 6 +- src/call_out.c | 4 +- src/closure.c | 24 +- src/closure.h | 4 + src/comm.c | 438 ++++--- src/comm.h | 6 +- src/driver.h | 37 +- src/dumpstat.c | 13 +- src/ed.c | 7 +- src/efuns.c | 756 ++++++++--- src/efuns.h | 11 +- src/files.c | 247 ++-- src/func_spec | 2 +- src/gcollect.c | 5 + src/heartbeat.c | 4 +- src/i-eval_cost.h | 82 ++ src/i-svalue_cmp.h | 2 +- src/interpret.c | 1102 +++++++++------- src/interpret.h | 57 +- src/lex.c | 73 +- src/lex.h | 2 +- src/main.c | 90 +- src/main.h | 2 +- src/make_func.y | 8 +- src/mapping.c | 285 ++-- src/mempools.c | 6 +- src/mregex.c | 94 +- src/mstrings.c | 129 +- src/mstrings.h | 191 +-- src/my-rusage.h | 2 +- src/object.c | 677 +++++----- src/object.h | 10 +- src/otable.c | 4 +- src/pkg-idna.c | 2 +- src/pkg-iksemel.c | 560 ++++++++ src/pkg-iksemel.h | 19 + src/pkg-mysql.c | 8 +- src/pkg-pcre.h | 4 + src/pkg-sqlite.c | 95 +- src/port.c | 58 +- src/port.h | 379 ++++-- src/prolang.y | 430 +++--- src/ptrtable.c | 12 +- src/random.c | 346 ++--- src/random.h | 24 +- src/random/CHANGE-LOG.txt | 55 + src/random/FILES.txt | 21 + src/random/LICENSE.txt | 32 + src/random/README.LDMUD | 10 + src/random/README.txt | 22 + src/random/SFMT-alti.h | 156 +++ src/random/SFMT-params.h | 97 ++ src/random/SFMT-params11213.h | 46 + src/random/SFMT-params1279.h | 46 + src/random/SFMT-params132049.h | 46 + src/random/SFMT-params19937.h | 46 + src/random/SFMT-params216091.h | 46 + src/random/SFMT-params2281.h | 46 + src/random/SFMT-params4253.h | 46 + src/random/SFMT-params44497.h | 46 + src/random/SFMT-params607.h | 46 + src/random/SFMT-params86243.h | 46 + src/random/SFMT-sse2.h | 121 ++ src/random/SFMT.c | 694 ++++++++++ src/random/SFMT.h | 87 ++ src/regexp.c | 9 +- src/settings/psyced | 3 + src/simul_efun.c | 12 + src/simulate.c | 235 ++-- src/simulate.h | 6 +- src/slaballoc.c | 170 +-- src/smalloc.c | 64 +- src/sprintf.c | 270 ++-- src/strfuns.c | 128 +- src/strfuns.h | 3 +- src/string_spec | 3 +- src/structs.c | 25 +- src/swap.c | 156 +-- src/util/indent/Makefile | 64 + src/util/indent/Makefile.in | 64 + src/util/indent/Projects | 24 + src/util/indent/args.c | 416 ++++++ src/util/indent/globs.c | 51 + src/util/indent/hosts/next/Makefile | 49 + src/util/indent/indent.c | 1382 ++++++++++++++++++++ src/util/indent/indent_globs.h | 406 ++++++ src/util/indent/io.c | 717 ++++++++++ src/util/indent/lexi.c | 584 +++++++++ src/util/indent/parse.c | 359 +++++ src/util/indent/pr_comment.c | 415 ++++++ src/util/indent/version.h | 2 + src/util/indent/wrapper | 11 + src/util/xerq/DONE | 40 + src/util/xerq/Makefile | 73 ++ src/util/xerq/Makefile.in | 73 ++ src/util/xerq/README | 23 + src/util/xerq/defs.h | 271 ++++ src/util/xerq/docs/socketd/socket_accept | 28 + src/util/xerq/docs/socketd/socket_address | 12 + src/util/xerq/docs/socketd/socket_connect | 29 + src/util/xerq/docs/socketd/socket_listen | 27 + src/util/xerq/docs/socketd/socket_sendto | 8 + src/util/xerq/docs/socketd/socket_transfer | 9 + src/util/xerq/docs/socketd/socket_udp | 29 + src/util/xerq/docs/socketd/socket_write | 8 + src/util/xerq/erq.c | 829 ++++++++++++ src/util/xerq/erq.h | 59 + src/util/xerq/execute.c | 572 ++++++++ src/util/xerq/lookup.c | 193 +++ src/util/xerq/lpc/README | 5 + src/util/xerq/lpc/TODO | 2 + src/util/xerq/lpc/_ifinger.c | 100 ++ src/util/xerq/lpc/_telnet.c | 47 + src/util/xerq/lpc/httpd.c | 89 ++ src/util/xerq/lpc/socket.h | 130 ++ src/util/xerq/lpc/socketd.c | 1196 +++++++++++++++++ src/util/xerq/lpc/socketd.man | 278 ++++ src/util/xerq/lpc/telnet_ob.c | 216 +++ src/util/xerq/lpc/udp.c | 43 + src/util/xerq/lpc/www/finger.c | 10 + src/util/xerq/lpc/www/who.c | 23 + src/util/xerq/socket.c | 916 +++++++++++++ src/version.sh | 17 +- src/xalloc.c | 57 +- src/xalloc.h | 30 +- src/xptmalloc.c | 7 +- 134 files changed, 16545 insertions(+), 3006 deletions(-) create mode 100644 src/i-eval_cost.h create mode 100644 src/pkg-iksemel.c create mode 100644 src/pkg-iksemel.h create mode 100644 src/random/CHANGE-LOG.txt create mode 100644 src/random/FILES.txt create mode 100644 src/random/LICENSE.txt create mode 100644 src/random/README.LDMUD create mode 100644 src/random/README.txt create mode 100644 src/random/SFMT-alti.h create mode 100644 src/random/SFMT-params.h create mode 100644 src/random/SFMT-params11213.h create mode 100644 src/random/SFMT-params1279.h create mode 100644 src/random/SFMT-params132049.h create mode 100644 src/random/SFMT-params19937.h create mode 100644 src/random/SFMT-params216091.h create mode 100644 src/random/SFMT-params2281.h create mode 100644 src/random/SFMT-params4253.h create mode 100644 src/random/SFMT-params44497.h create mode 100644 src/random/SFMT-params607.h create mode 100644 src/random/SFMT-params86243.h create mode 100644 src/random/SFMT-sse2.h create mode 100644 src/random/SFMT.c create mode 100644 src/random/SFMT.h create mode 100644 src/util/indent/Makefile create mode 100644 src/util/indent/Makefile.in create mode 100644 src/util/indent/Projects create mode 100644 src/util/indent/args.c create mode 100644 src/util/indent/globs.c create mode 100644 src/util/indent/hosts/next/Makefile create mode 100644 src/util/indent/indent.c create mode 100644 src/util/indent/indent_globs.h create mode 100644 src/util/indent/io.c create mode 100644 src/util/indent/lexi.c create mode 100644 src/util/indent/parse.c create mode 100644 src/util/indent/pr_comment.c create mode 100644 src/util/indent/version.h create mode 100644 src/util/indent/wrapper create mode 100644 src/util/xerq/DONE create mode 100644 src/util/xerq/Makefile create mode 100644 src/util/xerq/Makefile.in create mode 100644 src/util/xerq/README create mode 100644 src/util/xerq/defs.h create mode 100644 src/util/xerq/docs/socketd/socket_accept create mode 100644 src/util/xerq/docs/socketd/socket_address create mode 100644 src/util/xerq/docs/socketd/socket_connect create mode 100644 src/util/xerq/docs/socketd/socket_listen create mode 100644 src/util/xerq/docs/socketd/socket_sendto create mode 100644 src/util/xerq/docs/socketd/socket_transfer create mode 100644 src/util/xerq/docs/socketd/socket_udp create mode 100644 src/util/xerq/docs/socketd/socket_write create mode 100644 src/util/xerq/erq.c create mode 100644 src/util/xerq/erq.h create mode 100644 src/util/xerq/execute.c create mode 100644 src/util/xerq/lookup.c create mode 100644 src/util/xerq/lpc/README create mode 100644 src/util/xerq/lpc/TODO create mode 100644 src/util/xerq/lpc/_ifinger.c create mode 100644 src/util/xerq/lpc/_telnet.c create mode 100644 src/util/xerq/lpc/httpd.c create mode 100644 src/util/xerq/lpc/socket.h create mode 100644 src/util/xerq/lpc/socketd.c create mode 100644 src/util/xerq/lpc/socketd.man create mode 100644 src/util/xerq/lpc/telnet_ob.c create mode 100644 src/util/xerq/lpc/udp.c create mode 100644 src/util/xerq/lpc/www/finger.c create mode 100644 src/util/xerq/lpc/www/who.c create mode 100644 src/util/xerq/socket.c diff --git a/CHANGELOG b/CHANGELOG index 823a78e..14f665d 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,9 @@ +2009-05-22 (lynX) (4.0.12) + + adopted changes in LDMUD 3.3.718: + - many many many fixes + + support for iksemel xml parser library + + state of the art random generator + 2008-07-27 (lynX) (4.0.10) + added ERR_TLS_NOT_DETECTED code to sys/tls.h + added suitable message to tls_error() diff --git a/mudlib/sys/debug_info.h b/mudlib/sys/debug_info.h index 14dd944..8623963 100644 --- a/mudlib/sys/debug_info.h +++ b/mudlib/sys/debug_info.h @@ -25,6 +25,7 @@ #define DIT_ERROR 1 /* Return the last error call chain as an array */ #define DIT_UNCAUGHT_ERROR 2 /* Return the last uncaught error call chain */ #define DIT_STR_CURRENT 3 /* Return the current call chain as a string */ +#define DIT_CURRENT_DEPTH 4 /* Return the current control stack depth */ /* Indices into the array resulting from debug_info(DINFO_DATA, DID_STATUS) */ @@ -226,8 +227,13 @@ #define TRACE_PROGRAM 2 #define TRACE_OBJECT 3 #define TRACE_LOC 4 +#ifdef __EVAL_COST_TRACE__ +#define TRACE_EVALCOST 5 +#define TRACE_MAX 6 +#else #define TRACE_MAX 5 +#endif /* Values for entry TRACE_TYPE */ diff --git a/src/Makefile.in b/src/Makefile.in index 52e70ba..bcc917c 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -73,6 +73,14 @@ OPTIMIZE= $(@val_optimize@_OPTIMIZE) # recompile. #DEBUG = -DDEBUG # -DDEBUG_TELNET DEBUG= + +# Flags for compiling the SFMT random number generator. +SFMT_FLAGS = -fno-strict-aliasing +# for machines with sse2 support you may use: +#SFMT_FLAGS = -msse2 -fno-strict-aliasing -DHAVE_SSE2=1 +# for machines with altivec support you may use: +#SFMT_FLAGS = -faltivec -fno-strict-aliasing -DHAVE_ALTIVEC=1 + # MPATH=-DMUD_LIB='"$(MUD_LIB)"' -DBINDIR='"$(BINDIR)"' -DERQ_DIR='"$(ERQ_DIR)"' # @@ -93,7 +101,7 @@ SRC = access_check.c actions.c array.c backend.c bitstrings.c call_out.c \ interpret.c \ lex.c main.c mapping.c md5.c mempools.c mregex.c mstrings.c object.c \ otable.c\ - parser.c parse.c pkg-alists.c pkg-idna.c \ + parser.c parse.c pkg-alists.c pgk-iksemel.c pkg-idna.c pkg-expat.c \ pkg-mccp.c pkg-mysql.c pkg-pcre.c \ pkg-pgsql.c pkg-sqlite.c pkg-tls.c \ ptmalloc.c port.c ptrtable.c \ @@ -105,13 +113,12 @@ OBJ = access_check.o actions.o array.o backend.o bitstrings.o call_out.o \ interpret.o \ lex.o main.o mapping.o md5.o mempools.o mregex.o mstrings.o object.o \ otable.o \ - parser.o parse.o pkg-alists.o pkg-idna.o \ + parser.o parse.o pkg-alists.o pkg-iksemel.o pkg-idna.o pkg-expat.o \ pkg-mccp.o pkg-mysql.o pkg-pcre.o \ pkg-pgsql.o pkg-sqlite.o pkg-tls.o \ ptmalloc.o port.o ptrtable.o \ random.o regexp.o sha1.o simulate.o simul_efun.o stdstrings.o \ - strfuns.o structs.o sprintf.o swap.o wiz_list.o xalloc.o @ALLOCA@ \ - pkg-expat.o + strfuns.o structs.o sprintf.o swap.o wiz_list.o xalloc.o @ALLOCA@ all: make-patchlevel @PROGNAME@@EXEEXT@ @@ -123,7 +130,7 @@ it: @PROGNAME@@EXEEXT@ docs: @PROGNAME@@EXEEXT@ -help2man --name=@PROGNAME@ -N --help-option=--longhelp --include=../HELP --output=../@PROGNAME@.1 ./@PROGNAME@@EXEEXT@ - + install-all: install-driver install-headers install-utils install: install-driver @@ -213,6 +220,9 @@ lang.c lang.h: lang.y pcre/chartables.c : dftables@EXEEXT@ ./dftables@EXEEXT@ pcre/chartables.c +random.o : random.c config.h driver.h + $(CC) $(CFLAGS) $(SFMT_FLAGS) -c random.c -o random.o + #-------------------------------------------------------- # The dependency generation uses the program 'mkdepend' and assumes GNUmake. @@ -228,11 +238,11 @@ pcre/chartables.c : dftables@EXEEXT@ depend: $(SRC) $(GENSRC) @$(SHELL) -ec "if type mkdepend > /dev/null 2>&1; then \ echo Updating dependencies.; \ - mkdepend $(SKELETON) -I. $(EXCEPT) -m -p .c:%n.o -fMakefile; \ - mkdepend $(SKELETON) -I. $(EXCEPT) $(SELECT) -m -p .c:%n.o -fMakefile; \ + mkdepend $(SKELETON) -I. -Ipcre -Iptmalloc $(EXCEPT) -m -p .c:%n.o -fMakefile; \ + mkdepend $(SKELETON) -I. -Ipcre -Iptmalloc $(EXCEPT) $(SELECT) -m -p .c:%n.o -fMakefile; \ echo Updating dependencies in Makefile.in.; \ - mkdepend $(SKELETON) -I. $(EXCEPT) -m -p .c:%n.o -fMakefile.in; \ - mkdepend $(SKELETON) -I. $(EXCEPT) $(SELECT) -m -p .c:%n.o -fMakefile.in; \ + mkdepend $(SKELETON) -I. -Ipcre -Iptmalloc $(EXCEPT) -m -p .c:%n.o -fMakefile.in; \ + mkdepend $(SKELETON) -I. -Ipcre -Iptmalloc $(EXCEPT) $(SELECT) -m -p .c:%n.o -fMakefile.in; \ else\ echo mkdepend utility not available.; \ fi" @@ -242,8 +252,8 @@ depend: $(SRC) $(GENSRC) depend-generic: $(SRC) $(GENSRC) @$(SHELL) -ec "if type mkdepend > /dev/null 2>&1; then \ echo Updating dependencies in hosts/be/Makefile.; \ - mkdepend $(SKELETON) -I. $(EXCEPT) -m -p .c:$$\(OBJ\)/%n.o -fhosts/be/Makefile; \ - mkdepend $(SKELETON) -I. $(EXCEPT) $(SELECT) -m -p .c:$$\(OBJ\)/%n.o -fhosts/be/Makefile; \ + mkdepend $(SKELETON) -I. -Ipcre -Iptmalloc $(EXCEPT) -m -p .c:$$\(OBJ\)/%n.o -fhosts/be/Makefile; \ + mkdepend $(SKELETON) -I. -Ipcre -Iptmalloc $(EXCEPT) $(SELECT) -m -p .c:$$\(OBJ\)/%n.o -fhosts/be/Makefile; \ else\ echo mkdepend utility not available.; \ fi" @@ -271,20 +281,20 @@ array.o : i-svalue_cmp.h xalloc.h wiz_list.h swap.h svalue.h simulate.h \ hosts/be/be.h machine.h backend.o : ../mudlib/sys/debug_message.h ../mudlib/sys/driver_hook.h \ - xalloc.h wiz_list.h swap.h svalue.h stdstrings.h simulate.h random.h \ - otable.h object.h mstrings.h mregex.h mapping.h main.h lex.h \ - interpret.h heartbeat.h gcollect.h filestat.h exec.h ed.h comm.h \ - closure.h call_out.h array.h actions.h backend.h my-alloca.h typedefs.h \ - driver.h strfuns.h sent.h bytecode.h hash.h pkg-tls.h port.h config.h \ - hosts/unix.h hosts/be/be.h machine.h + i-eval_cost.h xalloc.h wiz_list.h swap.h svalue.h stdstrings.h \ + simulate.h random.h otable.h object.h mstrings.h mregex.h mapping.h \ + main.h lex.h interpret.h heartbeat.h gcollect.h filestat.h exec.h ed.h \ + comm.h closure.h call_out.h array.h actions.h backend.h my-alloca.h \ + typedefs.h driver.h strfuns.h sent.h bytecode.h hash.h pkg-tls.h port.h \ + config.h hosts/unix.h hosts/be/be.h machine.h bitstrings.o : xalloc.h svalue.h simulate.h mstrings.h interpret.h \ bitstrings.h typedefs.h driver.h strfuns.h sent.h bytecode.h hash.h \ backend.h port.h config.h main.h hosts/unix.h hosts/be/be.h machine.h -call_out.o : ../mudlib/sys/debug_info.h xalloc.h wiz_list.h swap.h svalue.h \ - strfuns.h stdstrings.h simulate.h object.h mstrings.h main.h \ - interpret.h gcollect.h exec.h comm.h closure.h backend.h array.h \ +call_out.o : ../mudlib/sys/debug_info.h i-eval_cost.h xalloc.h wiz_list.h \ + swap.h svalue.h strfuns.h stdstrings.h simulate.h object.h mstrings.h \ + main.h interpret.h gcollect.h exec.h comm.h closure.h backend.h array.h \ actions.h call_out.h typedefs.h driver.h sent.h bytecode.h hash.h \ pkg-tls.h port.h config.h hosts/unix.h hosts/be/be.h machine.h @@ -295,13 +305,13 @@ closure.o : i-svalue_cmp.h xalloc.h switch.h swap.h svalue.h structs.h \ bytecode.h port.h config.h hosts/unix.h hosts/be/be.h machine.h comm.o : util/erq/erq.h ../mudlib/sys/input_to.h \ - ../mudlib/sys/driver_hook.h ../mudlib/sys/comm.h xalloc.h wiz_list.h \ - swap.h svalue.h stdstrings.h simulate.h sent.h pkg-tls.h pkg-pgsql.h \ - pkg-mccp.h object.h mstrings.h main.h interpret.h gcollect.h filestat.h \ - exec.h ed.h closure.h array.h actions.h access_check.h comm.h \ - ../mudlib/sys/telnet.h my-alloca.h typedefs.h driver.h strfuns.h \ - bytecode.h hash.h backend.h config.h port.h hosts/unix.h hosts/be/be.h \ - machine.h + ../mudlib/sys/driver_hook.h ../mudlib/sys/comm.h i-eval_cost.h xalloc.h \ + wiz_list.h swap.h svalue.h stdstrings.h simulate.h sent.h pkg-tls.h \ + pkg-pgsql.h pkg-mccp.h object.h mstrings.h main.h interpret.h \ + gcollect.h filestat.h exec.h ed.h closure.h array.h actions.h \ + access_check.h comm.h ../mudlib/sys/telnet.h my-alloca.h typedefs.h \ + driver.h strfuns.h bytecode.h hash.h backend.h config.h port.h \ + hosts/unix.h hosts/be/be.h machine.h dumpstat.o : xalloc.h svalue.h structs.h stdstrings.h simulate.h ptrtable.h \ object.h mstrings.h mapping.h instrs.h filestat.h exec.h closure.h \ @@ -316,14 +326,14 @@ ed.o : ../mudlib/sys/regexp.h xalloc.h svalue.h stdstrings.h simulate.h \ efuns.o : ../mudlib/sys/time.h ../mudlib/sys/strings.h \ ../mudlib/sys/regexp.h ../mudlib/sys/objectinfo.h \ - ../mudlib/sys/driver_hook.h ../mudlib/sys/debug_info.h xalloc.h \ - wiz_list.h svalue.h swap.h structs.h strfuns.h simulate.h stdstrings.h \ - sha1.h random.h ptrtable.h otable.h object.h mstrings.h mregex.h md5.h \ - mempools.h mapping.h main.h lex.h interpret.h heartbeat.h exec.h \ - dumpstat.h comm.h closure.h call_out.h backend.h array.h actions.h \ - efuns.h my-rusage.h my-alloca.h typedefs.h driver.h hash.h sent.h \ - bytecode.h my-stdint.h pkg-tls.h port.h config.h hosts/unix.h \ - hosts/be/be.h machine.h + ../mudlib/sys/driver_hook.h ../mudlib/sys/debug_info.h i-eval_cost.h \ + xalloc.h wiz_list.h svalue.h swap.h structs.h strfuns.h simulate.h \ + stdstrings.h sha1.h random.h ptrtable.h otable.h object.h mstrings.h \ + mregex.h md5.h mempools.h mapping.h main.h lex.h interpret.h \ + heartbeat.h exec.h dumpstat.h comm.h closure.h call_out.h backend.h \ + array.h actions.h efuns.h my-rusage.h my-alloca.h typedefs.h driver.h \ + hash.h sent.h bytecode.h my-stdint.h pkg-tls.h port.h config.h \ + hosts/unix.h hosts/be/be.h machine.h files.o : ../mudlib/sys/files.h xalloc.h svalue.h stdstrings.h simulate.h \ mstrings.h mempools.h main.h lex.h interpret.h filestat.h comm.h \ @@ -331,8 +341,8 @@ files.o : ../mudlib/sys/files.h xalloc.h svalue.h stdstrings.h simulate.h \ bytecode.h hash.h backend.h pkg-tls.h port.h config.h hosts/unix.h \ hosts/be/be.h machine.h -gcollect.o : ../mudlib/sys/driver_hook.h xalloc.h wiz_list.h swap.h \ - structs.h stdstrings.h simul_efun.h simulate.h sent.h random.h \ +gcollect.o : ../mudlib/sys/driver_hook.h i-eval_cost.h xalloc.h wiz_list.h \ + swap.h structs.h stdstrings.h simul_efun.h simulate.h sent.h random.h \ ptrtable.h prolang.h pkg-pgsql.h parse.h otable.h object.h mstrings.h \ mregex.h mempools.h mapping.h main.h lex.h instrs.h interpret.h \ heartbeat.h filestat.h ed.h comm.h closure.h call_out.h backend.h \ @@ -342,35 +352,36 @@ gcollect.o : ../mudlib/sys/driver_hook.h xalloc.h wiz_list.h swap.h \ hash.o : hash.h -heartbeat.o : ../mudlib/sys/debug_info.h xalloc.h wiz_list.h svalue.h \ - strfuns.h simulate.h sent.h object.h mstrings.h interpret.h gcollect.h \ - exec.h comm.h backend.h array.h actions.h heartbeat.h typedefs.h \ - driver.h bytecode.h hash.h pkg-tls.h main.h port.h config.h \ +heartbeat.o : ../mudlib/sys/debug_info.h i-eval_cost.h xalloc.h wiz_list.h \ + svalue.h strfuns.h simulate.h sent.h object.h mstrings.h interpret.h \ + gcollect.h exec.h comm.h backend.h array.h actions.h heartbeat.h \ + typedefs.h driver.h bytecode.h hash.h pkg-tls.h main.h port.h config.h \ hosts/unix.h hosts/be/be.h machine.h -interpret.o : ../mudlib/sys/trace.h ../mudlib/sys/debug_info.h \ - ../mudlib/sys/driver_hook.h xalloc.h wiz_list.h switch.h swap.h \ - svalue.h structs.h stdstrings.h simul_efun.h simulate.h prolang.h \ - parse.h otable.h object.h mstrings.h mapping.h lex.h instrs.h \ - heartbeat.h gcollect.h filestat.h exec.h efuns.h ed.h comm.h closure.h \ - call_out.h backend.h array.h actions.h interpret.h my-alloca.h \ - typedefs.h driver.h strfuns.h hash.h ptrtable.h sent.h bytecode.h \ - pkg-tls.h main.h port.h config.h hosts/unix.h hosts/be/be.h machine.h +interpret.o : ../mudlib/sys/debug_info.h ../mudlib/sys/driver_hook.h \ + i-eval_cost.h xalloc.h wiz_list.h switch.h swap.h svalue.h structs.h \ + stdstrings.h simul_efun.h simulate.h prolang.h parse.h otable.h \ + object.h mstrings.h mapping.h lex.h instrs.h heartbeat.h gcollect.h \ + filestat.h exec.h efuns.h ed.h comm.h closure.h call_out.h backend.h \ + array.h actions.h interpret.h my-alloca.h typedefs.h driver.h strfuns.h \ + hash.h ptrtable.h sent.h bytecode.h pkg-tls.h main.h port.h config.h \ + hosts/unix.h hosts/be/be.h machine.h -lex.o : efun_defs.c ../mudlib/sys/driver_hook.h xalloc.h wiz_list.h \ - svalue.h strfuns.h stdstrings.h simul_efun.h simulate.h prolang.h \ - patchlevel.h object.h mstrings.h mempools.h main.h lang.h interpret.h \ - instrs.h hash.h gcollect.h filestat.h exec.h comm.h closure.h backend.h \ - array.h lex.h my-alloca.h typedefs.h driver.h ptrtable.h sent.h \ - bytecode.h pkg-tls.h port.h config.h hosts/unix.h hosts/be/be.h \ - machine.h +lex.o : efun_defs.c ../mudlib/sys/driver_hook.h i-eval_cost.h xalloc.h \ + wiz_list.h svalue.h strfuns.h stdstrings.h simul_efun.h simulate.h \ + prolang.h patchlevel.h object.h mstrings.h mempools.h main.h lang.h \ + interpret.h instrs.h hash.h gcollect.h filestat.h exec.h comm.h \ + closure.h backend.h array.h lex.h my-alloca.h typedefs.h driver.h \ + ptrtable.h sent.h bytecode.h pkg-tls.h port.h config.h hosts/unix.h \ + hosts/be/be.h machine.h -main.o : ../mudlib/sys/regexp.h pkg-mysql.h xalloc.h wiz_list.h swap.h \ - svalue.h stdstrings.h simul_efun.h simulate.h random.h pkg-tls.h \ - patchlevel.h otable.h object.h mstrings.h mregex.h mempools.h mapping.h \ - lex.h interpret.h gcollect.h filestat.h comm.h array.h backend.h main.h \ - my-alloca.h typedefs.h driver.h strfuns.h ptrtable.h exec.h sent.h \ - bytecode.h hash.h port.h config.h hosts/unix.h hosts/be/be.h machine.h +main.o : ../mudlib/sys/regexp.h i-eval_cost.h pkg-mysql.h xalloc.h \ + wiz_list.h swap.h svalue.h stdstrings.h simul_efun.h simulate.h \ + random.h pkg-tls.h patchlevel.h otable.h object.h mstrings.h mregex.h \ + mempools.h mapping.h lex.h interpret.h gcollect.h filestat.h comm.h \ + array.h backend.h main.h my-alloca.h typedefs.h driver.h strfuns.h \ + ptrtable.h exec.h sent.h bytecode.h hash.h port.h config.h hosts/unix.h \ + hosts/be/be.h machine.h mapping.o : i-svalue_cmp.h xalloc.h wiz_list.h svalue.h structs.h \ simulate.h object.h mstrings.h main.h interpret.h gcollect.h closure.h \ @@ -421,12 +432,12 @@ parse.o : xalloc.h wiz_list.h svalue.h stdstrings.h simulate.h object.h \ parse.h typedefs.h driver.h strfuns.h sent.h bytecode.h hash.h \ backend.h port.h config.h hosts/unix.h hosts/be/be.h machine.h -parser.o : lang.c ../mudlib/sys/driver_hook.h xalloc.h wiz_list.h switch.h \ - swap.h svalue.h structs.h stdstrings.h simul_efun.h simulate.h object.h \ - mstrings.h mapping.h main.h lex.h instrs.h interpret.h gcollect.h \ - exec.h closure.h backend.h array.h prolang.h my-alloca.h typedefs.h \ - driver.h strfuns.h hash.h ptrtable.h sent.h bytecode.h port.h config.h \ - hosts/unix.h hosts/be/be.h machine.h +parser.o : lang.c ../mudlib/sys/driver_hook.h i-eval_cost.h xalloc.h \ + wiz_list.h switch.h swap.h svalue.h structs.h stdstrings.h simul_efun.h \ + simulate.h object.h mstrings.h mapping.h main.h lex.h instrs.h \ + interpret.h gcollect.h exec.h closure.h backend.h array.h prolang.h \ + my-alloca.h typedefs.h driver.h strfuns.h hash.h ptrtable.h sent.h \ + bytecode.h port.h config.h hosts/unix.h hosts/be/be.h machine.h dftables.o : pcre/maketables.c pcre/internal.h pcre/pcre.h pcre/config.h @@ -487,9 +498,10 @@ ptrtable.o : simulate.h mempools.h ptrtable.h driver.h svalue.h strfuns.h \ random.o : random.h driver.h port.h config.h hosts/unix.h hosts/be/be.h \ machine.h -regexp.o : main.h xalloc.h simulate.h interpret.h regexp.h driver.h \ - typedefs.h svalue.h strfuns.h sent.h bytecode.h backend.h pkg-pcre.h \ - port.h config.h pcre/pcre.h hosts/unix.h hosts/be/be.h machine.h +regexp.o : i-eval_cost.h main.h xalloc.h simulate.h regexp.h driver.h \ + interpret.h typedefs.h svalue.h strfuns.h sent.h bytecode.h pkg-pcre.h \ + port.h config.h backend.h pcre/pcre.h hosts/unix.h hosts/be/be.h \ + machine.h sha1.o : sha1.h my-stdint.h driver.h port.h config.h hosts/unix.h \ hosts/be/be.h machine.h @@ -502,12 +514,12 @@ simul_efun.o : xalloc.h swap.h svalue.h stdstrings.h simulate.h prolang.h \ simulate.o : ../mudlib/sys/rtlimits.h ../mudlib/sys/regexp.h \ ../mudlib/sys/files.h ../mudlib/sys/driver_hook.h \ - ../mudlib/sys/debug_info.h xalloc.h wiz_list.h svalue.h swap.h \ - structs.h strfuns.h stdstrings.h simul_efun.h sent.h prolang.h \ + ../mudlib/sys/debug_info.h i-eval_cost.h xalloc.h wiz_list.h svalue.h \ + swap.h structs.h strfuns.h stdstrings.h simul_efun.h sent.h prolang.h \ pkg-sqlite.h pkg-tls.h otable.h object.h mstrings.h mregex.h mempools.h \ - mapping.h main.h lex.h interpret.h heartbeat.h gcollect.h filestat.h \ - ed.h comm.h closure.h call_out.h backend.h array.h actions.h simulate.h \ - my-alloca.h typedefs.h driver.h hash.h exec.h ptrtable.h bytecode.h \ + mapping.h main.h lex.h heartbeat.h gcollect.h filestat.h ed.h comm.h \ + closure.h call_out.h backend.h array.h actions.h simulate.h my-alloca.h \ + typedefs.h driver.h interpret.h hash.h exec.h ptrtable.h bytecode.h \ port.h config.h hosts/unix.h hosts/be/be.h machine.h sprintf.o : xalloc.h swap.h svalue.h structs.h stdstrings.h simul_efun.h \ diff --git a/src/actions.c b/src/actions.c index 2b1a2ee..5494aef 100644 --- a/src/actions.c +++ b/src/actions.c @@ -496,12 +496,20 @@ remove_shadow_actions (object_t *shadow, object_t *target) */ { -#ifdef USE_INVENTORIES +# ifdef USE_INVENTORIES object_t *item; -#endif +# endif + object_t *shadowing; + + /* Get the real underlying object, just as add_action does. */ + while ((target->flags & O_SHADOW) + && NULL != (shadowing = O_GET_SHADOW(target)->shadowing)) + { + target = shadowing; + } remove_shadow_action_sent(shadow, target); -#ifdef USE_INVENTORIES +# ifdef USE_INVENTORIES for (item = target->contains; item; item = item->next_inv) { if (shadow != item) @@ -517,7 +525,7 @@ remove_shadow_actions (object_t *shadow, object_t *target) remove_shadow_action_sent(shadow, item); } } -#endif +# endif } /* remove_shadow_actions() */ #endif @@ -1248,7 +1256,7 @@ execute_command (char *str, object_t *ob) /* Save the current context */ save_command_context(&context); context.rt.last = rt_context; - rt_context = (rt_context_t *)&context; + rt_context = (rt_context_t *)&context.rt; /* Default settings */ command_giver = ob; @@ -1423,8 +1431,8 @@ e_add_action (svalue_t *func, svalue_t *cmd, p_int flag) if ((size_t)(-flag) >= mstrsize(p->verb)) { free_action_sent(p); - errorf("Bad arg 3 to add_action(): value %ld larger than verb '%s'.\n" - , (long)flag, get_txt(p->verb)); + errorf("Bad arg 3 to add_action(): value %"PRIdPINT" larger than verb '%s'.\n" + , flag, get_txt(p->verb)); /* NOTREACHED */ return MY_TRUE; } @@ -1437,8 +1445,8 @@ e_add_action (svalue_t *func, svalue_t *cmd, p_int flag) else { free_action_sent(p); - errorf("Bad arg 3 to add_action(): value %ld too big.\n" - , (long)flag); + errorf("Bad arg 3 to add_action(): value %"PRIdPINT" too big.\n" + , flag); /* NOTREACHED */ return MY_TRUE; } @@ -1613,7 +1621,8 @@ f_execute_command (svalue_t *sp) len = mstrsize(argp->u.str); if (len >= sizeof(buf) - 1) - errorf("Command too long: '%.200s...'\n", get_txt(argp->u.str)); + errorf("Command too long (size: %zu): '%.200s...'\n", + len, get_txt(argp->u.str)); strncpy(buf, get_txt(argp->u.str), len); buf[len+1] = '\0'; @@ -1940,7 +1949,7 @@ f_remove_action (svalue_t *sp) */ { - object_t *ob; + object_t *ob, *shadow_ob; string_t *verb; sentence_t **sentp; action_t *s; @@ -1969,14 +1978,33 @@ f_remove_action (svalue_t *sp) efun_gen_arg_error(1, sp[-1].type, sp); /* NOTREACHED */ } - - /* Now search and remove the sentence */ + rc = 0; sentp = &ob->sent; + ob = current_object; + shadow_ob = NULL; + + /* Look for the underlying object, just as add_action does. */ + if (ob->flags & O_SHADOW && O_GET_SHADOW(ob)->shadowing) + { + object_t *shadowing; + + shadow_ob = ob; + + while ((ob->flags & O_SHADOW) + && NULL != (shadowing = O_GET_SHADOW(ob)->shadowing)) + { + ob = shadowing; + } + } + + /* Now search and remove the sentence */ while ( NULL != (s = (action_t *)*sentp) ) { - if (!SENT_IS_INTERNAL((*sentp)->type) && s->ob == ob && (!verb || s->verb == verb)) + if (!SENT_IS_INTERNAL((*sentp)->type) && s->ob == ob + && (!verb || s->verb == verb) + && (!shadow_ob || s->shadow_ob == shadow_ob)) { #ifdef CHECK_OBJECT_REF if (sentp == &ob->sent) @@ -2281,7 +2309,7 @@ f_disable_commands (svalue_t *sp) return sp; if (d_flag > 1) { - debug_message("%s Disable commands %s (ref %ld)\n" + debug_message("%s Disable commands %s (ref %"PRIdPINT")\n" , time_stamp(), get_txt(current_object->name) , current_object->ref); } @@ -2311,7 +2339,7 @@ f_enable_commands (svalue_t *sp) return sp; if (d_flag > 1) { - debug_message("%s Enable commands %s (ref %ld)\n" + debug_message("%s Enable commands %s (ref %"PRIdPINT")\n" , time_stamp(), get_txt(current_object->name) , current_object->ref); } @@ -2545,8 +2573,8 @@ f_set_modify_command (svalue_t *sp) else { if (sp->u.number != -1) - errorf("Bad num arg 1 to set_modify_command(): got %ld, " - "expected 0 or -1\n", sp->u.number); + errorf("Bad num arg 1 to set_modify_command(): got %"PRIdPINT + ", expected 0 or -1\n", sp->u.number); if (old) ref_object(old, "set_modify_command"); } } diff --git a/src/array.c b/src/array.c index 420f316..218abad 100644 --- a/src/array.c +++ b/src/array.c @@ -63,7 +63,7 @@ #include "array.h" #include "backend.h" #include "closure.h" /* closure_cmp(), closure_eq() */ -#include "interpret.h" /* for the efuns */ +#include "interpret.h" #include "main.h" #include "mapping.h" #include "mempools.h" @@ -133,7 +133,7 @@ _allocate_array(mp_int n MTRACE_DECL) svalue_t *svp; if (n < 0 || (max_array_size && (size_t)n > max_array_size)) - errorf("Illegal array size: %ld.\n", n); + errorf("Illegal array size: %"PRIdMPINT".\n", n); if (n == 0) { p = ref_array(&null_vector); @@ -145,10 +145,11 @@ _allocate_array(mp_int n MTRACE_DECL) p = ALLOC_VECTOR(n); if (!p) { #ifndef MALLOC_TRACE - (*allocate_array_error_handler)("Out of memory: array[%ld]\n", n); + (*allocate_array_error_handler) + ("Out of memory: array[%"PRIdMPINT"]\n", n); #else (*allocate_array_error_handler) - ("(%s:%d) Out of memory: array[%ld]\n" + ("(%s:%d) Out of memory: array[%"PRIdMPINT"]\n" MTRACE_PASS, n); #endif return 0; @@ -191,7 +192,7 @@ _allocate_array_unlimited(mp_int n MTRACE_DECL) svalue_t *svp; if (n < 0) - errorf("Illegal array size: %ld.\n", n); + errorf("Illegal array size: %"PRIdMPINT".\n", n); if (n == 0) { p = ref_array(&null_vector); @@ -204,10 +205,10 @@ _allocate_array_unlimited(mp_int n MTRACE_DECL) if (!p) { #ifndef MALLOC_TRACE (*allocate_array_error_handler) - ("Out of memory: unlimited array[%ld]\n", n); + ("Out of memory: unlimited array[%"PRIdMPINT"]\n", n); #else (*allocate_array_error_handler) - ("(%s:%d) Out of memory: unlimited array[%ld]\n" + ("(%s:%d) Out of memory: unlimited array[%"PRIdMPINT"]\n" MTRACE_PASS, n); #endif return 0; @@ -247,7 +248,7 @@ _allocate_uninit_array (mp_int n MTRACE_DECL) vector_t *p; if (n < 0 || (max_array_size && (size_t)n > max_array_size)) - errorf("Illegal array size: %ld.\n", n); + errorf("Illegal array size: %"PRIdMPINT".\n", n); if (n == 0) { p = ref_array(&null_vector); @@ -260,10 +261,10 @@ _allocate_uninit_array (mp_int n MTRACE_DECL) if (!p) { #ifndef MALLOC_TRACE (*allocate_array_error_handler) - ("Out of memory: uninited array[%ld]\n", n); + ("Out of memory: uninited array[%"PRIdMPINT"]\n", n); #else (*allocate_array_error_handler) - ("(%s:%d) Out of memory: uninited array[%ld]\n" + ("(%s:%d) Out of memory: uninited array[%"PRIdMPINT"]\n" MTRACE_PASS, n); #endif return 0; @@ -293,7 +294,8 @@ _free_vector (vector_t *p) #ifdef DEBUG if (p->ref > 0) - fatal("Vector with %ld refs passed to _free_vector()\n", p->ref); + fatal("Vector with %"PRIdPINT" refs passed to _free_vector()\n", + p->ref); if (p == &null_vector) fatal("Tried to free the zero-size shared vector.\n"); #endif @@ -1860,7 +1862,7 @@ v_allocate (svalue_t *sp, int num_arg) size = svp->u.number; if (size < 0 || (max_array_size && (size_t)size > max_array_size)) - errorf("Illegal array size: %ld\n", (long)size); + errorf("Illegal array size: %"PRIdPINT"\n", size); if (size == 0 && dim < num_dim-1) errorf("Only the last dimension can have empty arrays.\n"); @@ -2186,7 +2188,8 @@ x_map_array (svalue_t *sp, int num_arg) res = allocate_array(cnt); if (!res) - errorf("(map_array) Out of memory: array[%ld] for result\n", cnt); + errorf("(map_array) Out of memory: array[%"PRIdMPINT + "] for result\n", cnt); push_array(inter_sp, res); /* In case of errors */ for (w = arr->item, x = res->item; --cnt >= 0; w++, x++) @@ -2224,7 +2227,8 @@ x_map_array (svalue_t *sp, int num_arg) res = allocate_array(cnt); if (!res) - errorf("(map_array) Out of memory: array[%ld] for result\n", cnt); + errorf("(map_array) Out of memory: array[%"PRIdMPINT + "] for result\n", cnt); push_array(inter_sp, res); /* In case of errors */ /* Loop through arr and res, mapping the values from arr */ diff --git a/src/array.h b/src/array.h index 0b8aef4..059d07d 100644 --- a/src/array.h +++ b/src/array.h @@ -7,49 +7,6 @@ #include "typedefs.h" #include "svalue.h" -/* --- Macros --- */ - -/* vector_t *ref_array(vector_t *a) - * Add another ref to array and return the vector . - */ - -#define ref_array(a) ((a)->ref++, (a)) - -/* void free_array(vector_t *a) - * Subtract one ref from array , and free the array fully if - * the refcount reaches zero. - */ - -#define free_array(a) MACRO( if (--((a)->ref) <= 0) _free_vector(a); ) - -/* p_int deref_array(vector_t *a) - * Subtract one ref from array , but don't check if it needs to - * be freed. Result is the number of refs left. - */ - -#define deref_array(a) (--(a)->ref) - -/* See array.c for a description of what the following macros do. */ - -/* Helper for LOCAL_VECn() */ -#ifdef DEBUG -# define VEC_DEBUGREF(ref) ref, -#else -# define VEC_DEBUGREF(ref) -#endif -#include "svalue.h" - -#define VEC_HEAD(size) size, 1, VEC_DEBUGREF(1) NULL - -#define VEC_SIZE(v) ((v)->size) - -#define LOCAL_VEC1(name, type1) \ - struct { vector_t v; } name \ - = { { VEC_HEAD(1), { { type1, { 0 } } } } } - -#define LOCAL_VEC2(name, type1, type2) \ - struct { vector_t v; svalue_t item[1]; } name \ - = { { VEC_HEAD(2), { { type1, { 0 } } } }, { { type2, { 0 } } } } /* --- Types --- */ @@ -70,6 +27,30 @@ struct vector_s { }; +/* --- Macros --- */ +/* See array.c for a description of what the following macros do. */ + +/* Helper for LOCAL_VECn() */ +#ifdef DEBUG +# define VEC_DEBUGREF(ref) ref, +#else +# define VEC_DEBUGREF(ref) +#endif + + +#define VEC_HEAD(size) size, 1, VEC_DEBUGREF(1) NULL + +#define VEC_SIZE(v) ((v)->size) + +#define LOCAL_VEC1(name, type1) \ + struct { vector_t v; } name \ + = { { VEC_HEAD(1), { { type1, { 0 } } } } } + +#define LOCAL_VEC2(name, type1, type2) \ + struct { vector_t v; svalue_t item[1]; } name \ + = { { VEC_HEAD(2), { { type1, { 0 } } } }, { { type2, { 0 } } } } + + /* --- Variables --- */ extern vector_t null_vector; @@ -77,6 +58,7 @@ extern vector_t null_vector; extern int num_arrays; extern void (*allocate_array_error_handler) (const char *, ...); + /* --- Prototypes --- */ #if defined(MALLOC_TRACE) @@ -134,4 +116,33 @@ extern void clear_array_size (void); extern void count_array_size (vector_t *vec); #endif + +/* --- static helper functions --- */ + +/* vector_t *ref_array(vector_t *a) + * Add another ref to array and return the vector . + */ +static INLINE vector_t* ref_array(vector_t *a) { + ++a->ref; + return a; +} + +/* void free_array(vector_t *a) + * Subtract one ref from array , and free the array fully if + * the refcount reaches zero. + */ +static INLINE void free_array(vector_t *a) { + if (--(a->ref) <= 0) + _free_vector(a); +} + +/* p_int deref_array(vector_t *a) + * Subtract one ref from array , but don't check if it needs to + * be freed. Result is the number of refs left. + */ +static INLINE p_int deref_array(vector_t *a) { + return --a->ref; +} + + #endif /* ARRAY_H__ */ diff --git a/src/backend.c b/src/backend.c index 092b579..d1bc46d 100644 --- a/src/backend.c +++ b/src/backend.c @@ -74,6 +74,8 @@ #include "wiz_list.h" #include "xalloc.h" +#include "i-eval_cost.h" + #include "../mudlib/sys/driver_hook.h" #include "../mudlib/sys/debug_message.h" @@ -122,9 +124,9 @@ uint num_last_data_cleaned = 0; /* Number of object data-cleaned in last process_objects(). */ -statistic_t stat_last_processed = { 0 }; -statistic_t stat_last_data_cleaned = { 0 }; -statistic_t stat_in_list = { 0 }; +statistic_t stat_last_processed = { 0, 0, 0.0 }; +statistic_t stat_last_data_cleaned = { 0, 0, 0.0 }; +statistic_t stat_in_list = { 0, 0, 0.0 }; /* Decaying average number of objects processed and objects in the list. */ @@ -151,12 +153,12 @@ Bool mud_is_up = MY_FALSE; */ #endif -statistic_t stat_load = { 0 }; +statistic_t stat_load = { 0, 0, 0.0 }; /* The load average (player commands/second), weighted over the * last period of time. */ -statistic_t stat_compile = { 0 }; +statistic_t stat_compile = { 0, 0, 0.0 }; /* The average of compiled lines/second, weighted over the last period * of time. */ @@ -337,7 +339,7 @@ handle_usr1 (int sig UNUSED) #ifndef RETSIGTYPE_VOID return 0; #endif -} /* handle_usr1() */ +} /* handle_usr2() */ /*-------------------------------------------------------------------------*/ static RETSIGTYPE @@ -614,7 +616,7 @@ backend (void) /* puts("Handling outgoing connections."); */ check_for_out_connections(); } else - extra_jobs_to_do = MY_FALSE; + extra_jobs_to_do = MY_FALSE; } /* if (extra_jobs_to_do */ @@ -841,8 +843,9 @@ void check_alarm (void) } else if (curtime - last_alarm_time > 15) { - debug_message("%s Last alarm was %ld seconds ago - restarting it.\n" - , time_stamp(), curtime - last_alarm_time); + debug_message("%s Last alarm was %"PRIdMPINT" seconds ago " + "- restarting it.\n", + time_stamp(), curtime - last_alarm_time); alarm(0); /* stop alarm in case it is still alive, but just slow */ comm_time_to_call_heart_beat = MY_TRUE; @@ -931,7 +934,7 @@ static Bool did_swap; error_recovery_info.rt.last = rt_context; error_recovery_info.rt.type = ERROR_RECOVERY_BACKEND; - rt_context = (rt_context_t *)&error_recovery_info; + rt_context = (rt_context_t *)&error_recovery_info.rt; if (setjmp(error_recovery_info.con.text)) { diff --git a/src/bitstrings.c b/src/bitstrings.c index c8832cc..e077010 100644 --- a/src/bitstrings.c +++ b/src/bitstrings.c @@ -64,10 +64,10 @@ last_bit (string_t *str) */ { - mp_int pos; - long len; - char * cstr; - int c; + mp_int pos; + long len; + const char * cstr; + int c; pos = -1; @@ -624,7 +624,7 @@ f_count_bits (svalue_t *sp) } /* f_count_bits() */ /*-------------------------------------------------------------------------*/ -static INLINE void +static void copy_bits ( string_t * dest, p_int deststart , string_t * src, p_int srcstart , p_int len diff --git a/src/bytecode.h b/src/bytecode.h index bd4d024..686bc19 100644 --- a/src/bytecode.h +++ b/src/bytecode.h @@ -232,7 +232,7 @@ typedef bytecode_t * bytecode_p; RSTORE_2BYTE(p,_us);) #else # error "Unsupported size of short." -#endif +#endif /* SIZEOF_SHORT */ #if SIZEOF_LONG == 4 # define GET_LONG(d,p) GET_4BYTE(d,p) @@ -256,7 +256,7 @@ typedef bytecode_t * bytecode_p; RSTORE_4BYTE(p,_ui);) #else # error "Unsupported size of long." -#endif +#endif /* SIZEOF_LONG */ #define LOAD_INT16(d,p) LOAD_2BYTE(d,p) @@ -280,7 +280,7 @@ typedef bytecode_t * bytecode_p; # define LOAD_INT32(d,p) LOAD_2BYTE(d,p) #endif -#endif +#endif /* CHAR_BIT */ #ifndef GET_CODE # error "No bytecode type defined." diff --git a/src/call_out.c b/src/call_out.c index e410302..bfd45dc 100644 --- a/src/call_out.c +++ b/src/call_out.c @@ -46,6 +46,8 @@ #include "wiz_list.h" #include "xalloc.h" +#include "i-eval_cost.h" + #include "../mudlib/sys/debug_info.h" /*-------------------------------------------------------------------------*/ @@ -262,7 +264,7 @@ call_out (void) error_recovery_info.rt.last = rt_context; error_recovery_info.rt.type = ERROR_RECOVERY_BACKEND; - rt_context = (rt_context_t *)&error_recovery_info; + rt_context = (rt_context_t *)&error_recovery_info.rt; if (setjmp(error_recovery_info.con.text)) { diff --git a/src/closure.c b/src/closure.c index d69ae36..da48f86 100644 --- a/src/closure.c +++ b/src/closure.c @@ -344,6 +344,9 @@ static work_area_t current /* Forward declarations */ static void lambda_error VARPROT((const char *error_str, ...), printf, 1, 2) NORETURN; +static void lambda_cerror(const char *s) FORMATDEBUG(printf,1,0) NORETURN; +static void lambda_cerrorl(const char *s1, const char *s2 UNUSED, int line1 UNUSED, + int line2 UNUSED) NORETURN FORMATDEBUG(printf,1,0); static void free_symbols(void); static Bool is_lvalue (svalue_t *argp, int index_lvalue); static void compile_lvalue(svalue_t *, int); @@ -939,7 +942,7 @@ replace_program_lambda_adjust (replace_ob_t *r_ob) error_recovery_info.rt.last = rt_context; error_recovery_info.rt.type = ERROR_RECOVERY_BACKEND; - rt_context = (rt_context_t *)&error_recovery_info; + rt_context = (rt_context_t *)&error_recovery_info.rt; if (setjmp(error_recovery_info.con.text)) { bytecode_p p; @@ -1347,8 +1350,9 @@ realloc_values (void) new_values = xalloc(new_max * sizeof(*new_values)); if (!new_values) - lambda_error("Out of memory (%lu bytes) for %ld new values\n" - , new_max, new_max * sizeof(*new_values)); + lambda_error("Out of memory (%"PRIdMPINT + " bytes) for %"PRIdMPINT" new values\n", + new_max, new_max * sizeof(*new_values)); current.values_left += current.value_max; memcpy( (current.valuep = new_values + current.value_max) @@ -1380,7 +1384,8 @@ realloc_code (void) new_max = current.code_max * 2; new_code = rexalloc(current.code, (size_t)new_max); if (!new_code) - lambda_error("Out of memory (%ld bytes) for new code\n", new_max); + lambda_error("Out of memory (%"PRIdMPINT" bytes) for new code\n", + new_max); current.code_left += current.code_max; current.code_max = new_max; @@ -1595,7 +1600,7 @@ make_symbol (string_t *name) if (!symp) { current.symbol_max /= 2; xfree(sym); - lambda_error("Out of memory (%ld bytes) for symbol table\n" + lambda_error("Out of memory (%"PRIdMPINT" bytes) for symbol table\n" , current.symbol_max); } current.symbol_mask = i = current.symbol_max - (long)sizeof sym; @@ -5200,8 +5205,8 @@ lambda (vector_t *args, svalue_t *block, object_t *origin) current.code_left = CODE_BUFFER_START_SIZE-3; current.levels_left = MAX_LAMBDA_LEVELS; if ( !(current.code = current.codep = xalloc((size_t)current.code_max)) ) - lambda_error("Out of memory (%ld bytes) for initial codebuffer\n" - , current.code_max); + lambda_error("Out of memory (%"PRIdMPINT + " bytes) for initial codebuffer\n", current.code_max); /* Store the lambda code header */ STORE_UINT8(current.codep, 0); /* dummy for num values */ @@ -5212,8 +5217,9 @@ lambda (vector_t *args, svalue_t *block, object_t *origin) if ( !(current.values = xalloc(current.value_max * sizeof current.values[0])) ) { - lambda_error("Out of memory (%lu bytes) for initial value buffer\n" - , current.value_max * sizeof current.values[0]); + lambda_error("Out of memory (%"PRIdMPINT + " bytes) for initial value buffer\n", + current.value_max * sizeof current.values[0]); } current.valuep = current.values + current.value_max; diff --git a/src/closure.h b/src/closure.h index 1914ed1..c81641b 100644 --- a/src/closure.h +++ b/src/closure.h @@ -9,6 +9,10 @@ #include "svalue.h" #endif /* USE_NEW_INLINES */ +/* In case offsetof() is not a compiler builtin include stddef.h which + * supplies a define as fallback. Needed for LAMBDA_VALUE_OFFSET */ +#include + /* --- Types --- */ /* --- struct lambda_s: --- diff --git a/src/comm.c b/src/comm.c index 6cee71a..f67d871 100644 --- a/src/comm.c +++ b/src/comm.c @@ -140,6 +140,8 @@ #include "wiz_list.h" #include "xalloc.h" +#include "i-eval_cost.h" + #include "../mudlib/sys/comm.h" #include "../mudlib/sys/driver_hook.h" #include "../mudlib/sys/input_to.h" @@ -398,22 +400,26 @@ static void (*telopts_wont[NTELOPTS])(int); /* Tables with the telnet statemachine handlers. */ -#define TS_DATA 0 -#define TS_IAC 1 -#define TS_WILL 2 -#define TS_WONT 3 -#define TS_DO 4 -#define TS_DONT 5 -#define TS_SB 6 -#define TS_SB_IAC 7 -#define TS_READY 8 -#define TS_SYNCH 9 -#define TS_INVALID 10 +enum telnet_states { + TS_DATA = 0, + TS_IAC, + TS_WILL, + TS_WONT, + TS_DO, + TS_DONT, + TS_SB, + TS_SB_IAC, + TS_READY, + TS_SYNCH, + TS_INVALID +}; /* Telnet states */ -#define TN_START_VALID(x) ((x & ~1) == TS_SB) +static inline int TN_START_VALID(int x) { + return (x & ~TS_IAC) == TS_SB; +} /* --- Misc --- */ @@ -526,16 +532,13 @@ static void *writer_thread(void *arg); # define s6_addr32 __u6_addr.__u6_addr32 #endif -#ifndef CREATE_IPV6_MAPPED - -#define CREATE_IPV6_MAPPED(v6,v4) \ - ((v6).s6_addr32[0] = 0, \ - (v6).s6_addr32[1] = 0, \ - (v6).s6_addr32[2] = 0x0000ffff, \ - (v6).s6_addr32[2] = 0xffff0000, \ - (v6).s6_addr32[3] = v4 ) - -#endif +static inline void CREATE_IPV6_MAPPED(struct in_addr *v6, uint32 v4) { + v6->s6_addr32[0] = 0; + v6->s6_addr32[1] = 0; + v6->s6_addr32[2] = 0x0000ffff; + v6->s6_addr32[2] = 0xffff0000; + v6->s6_addr32[3] = v4; +} /* These are the typical IPv6 structures - we use them transparently. * @@ -663,6 +666,8 @@ dump_bytes (void * data, size_t length, int indent) } /* dump_bytes() */ /*-------------------------------------------------------------------------*/ +static void comm_fatal (interactive_t *ip, char *fmt, ...) + FORMATDEBUG(printf,2,3) ; static void comm_fatal (interactive_t *ip, char *fmt, ...) @@ -729,20 +734,20 @@ comm_fatal (interactive_t *ip, char *fmt, ...) dump_bytes(&(ip->prompt), sizeof(ip->prompt), 21); fprintf(stderr, " .addr: "); dump_bytes(&(ip->addr), sizeof(ip->addr), 21); - fprintf(stderr, " .msg_discarded: %02x\n", (unsigned char)ip->msg_discarded); - fprintf(stderr, " .set_input_to: %02x\n", (unsigned char)ip->set_input_to); - fprintf(stderr, " .closing: %02x\n", (unsigned char)ip->closing); - fprintf(stderr, " .tn_enabled: %02x\n", (unsigned char)ip->tn_enabled); - fprintf(stderr, " .do_close: %02x", (unsigned char)ip->do_close); + fprintf(stderr, " .msg_discarded: %02hhx\n", (unsigned char)ip->msg_discarded); + fprintf(stderr, " .set_input_to: %02hhx\n", (unsigned char)ip->set_input_to); + fprintf(stderr, " .closing: %02hhx\n", (unsigned char)ip->closing); + fprintf(stderr, " .tn_enabled: %02hhx\n", (unsigned char)ip->tn_enabled); + fprintf(stderr, " .do_close: %02hhx", (unsigned char)ip->do_close); if (ip->do_close & (FLAG_DO_CLOSE|FLAG_PROTO_ERQ)) fprintf(stderr, " ("); if (ip->do_close & FLAG_DO_CLOSE) fprintf(stderr, "DO_CLOSE"); if (ip->do_close & (FLAG_DO_CLOSE|FLAG_PROTO_ERQ)) fprintf(stderr, ", "); if (ip->do_close & FLAG_PROTO_ERQ) fprintf(stderr, "PROTO_ERQ"); if (ip->do_close & (FLAG_DO_CLOSE|FLAG_PROTO_ERQ)) fprintf(stderr, ")"); putc('\n', stderr); - fprintf(stderr, " .noecho: %02x", (unsigned char)ip->noecho); + fprintf(stderr, " .noecho: %02hhx", (unsigned char)ip->noecho); fprintf(stderr, " %s\n", decode_noecho(ip->noecho)); - fprintf(stderr, " .tn_state: %d", ip->tn_state); + fprintf(stderr, " .tn_state: %hhd", ip->tn_state); switch(ip->tn_state) { case TS_DATA: fprintf(stderr, " (TS_DATA)\n"); break; case TS_IAC: fprintf(stderr, " (TS_IAC)\n"); break; @@ -757,7 +762,7 @@ comm_fatal (interactive_t *ip, char *fmt, ...) case TS_INVALID: fprintf(stderr, " (TS_INVALID)\n"); break; default: putc('\n', stderr); } - fprintf(stderr, " .save_tn_state: %d", ip->save_tn_state); + fprintf(stderr, " .save_tn_state: %hhd", ip->save_tn_state); switch(ip->save_tn_state) { case TS_DATA: fprintf(stderr, " (TS_DATA)\n"); break; case TS_IAC: fprintf(stderr, " (TS_IAC)\n"); break; @@ -772,13 +777,13 @@ comm_fatal (interactive_t *ip, char *fmt, ...) case TS_INVALID: fprintf(stderr, " (TS_INVALID)\n"); break; default: putc('\n', stderr); } - fprintf(stderr, " .supress_go_ahead: %02x\n", (unsigned char)ip->supress_go_ahead); + fprintf(stderr, " .supress_go_ahead: %02hhx\n", (unsigned char)ip->supress_go_ahead); fprintf(stderr, " .text_end: %hd (%p)\n", ip->text_end, ip->text+ip->text_end); fprintf(stderr, " .command_start: %hd (%p)\n", ip->command_start, ip->text+ip->command_start); fprintf(stderr, " .command_end: %hd (%p)\n", ip->command_end, ip->text+ip->command_end); fprintf(stderr, " .tn_start: %hd (%p)\n", ip->tn_start, ip->text+ip->tn_start); fprintf(stderr, " .tn_end: %hd (%p)\n", ip->tn_end, ip->text+ip->tn_end); - fprintf(stderr, " .chars_ready: %ld\n", (long)ip->chars_ready); + fprintf(stderr, " .chars_ready: %"PRId32"\n",ip->chars_ready); #ifdef USE_SNOOPING fprintf(stderr, " .snoop_on: %p", ip->snoop_on); if (ip->snoop_on && ip->snoop_on->ob) fprintf(stderr, " (%s)", get_txt(ip->snoop_on->ob->name)); @@ -787,7 +792,7 @@ comm_fatal (interactive_t *ip, char *fmt, ...) if (ip->snoop_by) fprintf(stderr, " (%s)", get_txt(ip->snoop_by->name)); putc('\n', stderr); #endif - fprintf(stderr, " .last_time: %ld\n", (long)ip->last_time); + fprintf(stderr, " .last_time: %"PRIdMPINT"\n", ip->last_time); #ifdef USE_SOCKET_LIMITS fprintf(stderr, " .numCmds: %ld\n", ip->numCmds); fprintf(stderr, " .maxNumCmds: %ld\n", ip->maxNumCmds); @@ -808,10 +813,10 @@ comm_fatal (interactive_t *ip, char *fmt, ...) dump_bytes(&(ip->charset), sizeof(ip->charset), 21); fprintf(stderr, " .combine_cset: "); dump_bytes(&(ip->combine_cset), sizeof(ip->combine_cset), 21); - fprintf(stderr, " .quote_iac: %02x\n", (unsigned char)ip->quote_iac); - fprintf(stderr, " .catch_tell_activ: %02x\n", (unsigned char)ip->catch_tell_activ); - fprintf(stderr, " .gobble_char: %02x\n", (unsigned char)ip->gobble_char); - fprintf(stderr, " .ts_data: %02x\n", (unsigned char)ip->ts_data); + fprintf(stderr, " .quote_iac: %02hhx\n", (unsigned char)ip->quote_iac); + fprintf(stderr, " .catch_tell_activ: %02hhx\n", (unsigned char)ip->catch_tell_activ); + fprintf(stderr, " .gobble_char: %02hhx\n", (unsigned char)ip->gobble_char); + fprintf(stderr, " .ts_data: %02hhx\n", (unsigned char)ip->ts_data); fprintf(stderr, " .text: "); dump_bytes(&(ip->text), sizeof(ip->text), 21); fprintf(stderr, " .message_buf: "); @@ -1417,9 +1422,8 @@ interactive_cleanup (interactive_t *ip) default: { - int e = tmp->errorno; dprintf2(2, "%s comm: write: unexpected errno %d\n" - , (p_int)time_stamp(), (p_int)e); + , (p_int)time_stamp(), (p_int)tmp->errorno); break; } } /* switch (ip->errorno) */ @@ -1959,15 +1963,20 @@ add_message (const char *fmt, ...) } else { - buff[(sizeof buff) - 1] = '\0'; /* Overrun sentinel */ - vsprintf(buff+1,fmt,va); + size_t len; + len = vsnprintf(buff+1, sizeof(buff)-1, fmt,va); va_end(va); - if (buff[(sizeof buff) - 1]) + /* old sprintf() implementations returned -1 if the output was + * truncated. Since size_t is an unsigned type, the check for + * len == -1 is implicitly included by >= sizeof(...)-1, because + * -1 will be wrapped to SIZE_T_MAX which is the maximum sizeof() + * can return and can never be valid as return value here. */ + if (len >= sizeof(buff)-1) { - debug_message("%s Message too long: '%.200s...'\n" - , time_stamp(), buff); - comm_fatal(ip, "Message too long!\n"); - return; + char err[] = "\n*** Message truncated ***\n"; + debug_message("%s Message too long (Length: %zu): '%.200s...'\n" + , time_stamp(), len, buff); + (void)strcpy(buff+(sizeof(buff)-sizeof(err)), err); } source = buff+1; srclen = strlen(buff+1); @@ -2071,9 +2080,9 @@ add_message (const char *fmt, ...) #ifdef DEBUG if (d_flag > 1) - debug_message("%s [%s(%ld)]: %s" + debug_message("%s [%s (%zu)]: %s" , time_stamp(), get_txt(command_giver->name) - , (long)srclen, source); + , srclen, source); #endif /* --- Send the final message --- */ @@ -2095,8 +2104,8 @@ if (sending_telnet_command) { char *cp; long left; - printf("%s TDEBUG: '%s' Sending telnet (%lu bytes): " - , time_stamp(), get_txt(ip->ob->name), (unsigned long) strlen(source)); + printf("%s TDEBUG: '%s' Sending telnet (%zu bytes): " + , time_stamp(), get_txt(ip->ob->name), strlen(source)); for (cp = source, left = srclen; left > 0; cp++, left--) printf(" %02x", (unsigned char)*cp); printf("\n"); @@ -2310,14 +2319,14 @@ if (sending_telnet_command) ip->out_compress->next_out = ip->out_compress_buf + length - n; if (n != length) fprintf(stderr, "%s write socket (compressed): wrote %ld, " - "should be %ld.\n" - , time_stamp(), (long)n, (long)chunk); + "should be %td.\n" + , time_stamp(), (long)n, chunk); } else #endif if (n != chunk) - fprintf(stderr, "%s write socket: wrote %ld, should be %ld.\n" - , time_stamp(), (long)n, (long)chunk); + fprintf(stderr, "%s write socket: wrote %ld, should be %td.\n" + , time_stamp(), (long)n, chunk); /* Continue with the processing of source */ dest = &ip->message_buf[0]; @@ -2361,7 +2370,8 @@ reset_input_buffer (interactive_t *ip) { if (ip->command_start) { - DTN(("reset input buffer: cmd_start %d, tn_start %d, tn_end %d, text_end %d\n", ip->command_start, ip->tn_start, ip->tn_end, ip->text_end)); + DTN(("reset input buffer: cmd_start %hd, tn_start %hd, tn_end %hd, text_end %hd\n", + ip->command_start, ip->tn_start, ip->tn_end, ip->text_end)); ip->tn_start -= ip->command_start; ip->tn_end -= ip->command_start; ip->text_end -= ip->command_start; @@ -2714,7 +2724,7 @@ get_message (char *buff, size_t *len) if (l <= 0) { #ifdef DEBUG_ERQ - fprintf(stderr, "%s read %ld bytes from erq demon\n" + fprintf(stderr, "%s read %"PRIdMPINT" bytes from erq demon\n" , time_stamp(), l); if (l) perror(""); @@ -2745,7 +2755,7 @@ get_message (char *buff, size_t *len) #ifdef DEBUG_ERQ fprintf( stderr , "%s invalid length of message from" - "erq demon: %ld bytes\n" + "erq demon: %"PRIdMPINT" bytes\n" , time_stamp(), msglen); #endif /* DEBUG_ERQ */ stop_erq_demon(MY_TRUE); @@ -2784,14 +2794,14 @@ get_message (char *buff, size_t *len) } #endif } else { - int32 naddr; + uint32 naddr; struct in_addr net_addr; - memcpy((char*)&naddr, rp+8, 4); + memcpy((char*)&naddr, rp+8, sizeof(naddr)); #ifndef USE_IPV6 net_addr.s_addr = naddr; #else - CREATE_IPV6_MAPPED(net_addr, naddr); + CREATE_IPV6_MAPPED(&net_addr, naddr); #endif add_ip_entry(net_addr, rp+12); } @@ -3003,8 +3013,8 @@ get_message (char *buff, size_t *len) udp_data = new_n_mstring(udp_buf, cnt); if (!udp_data) { - debug_message("%s Out of memory (%ld bytes) for UDP message.\n" - , time_stamp(), (long)cnt); + debug_message("%s Out of memory (%d bytes) for UDP message.\n" + , time_stamp(), cnt); } else { @@ -3073,13 +3083,33 @@ get_message (char *buff, size_t *len) l = MAX_TEXT - ip->text_end; + /* In CHARMODE with combine-charset, the driver gets + * confused when receiving MAX_TEXT or more combinable + * characters. + * I couldn't quite figure out what and why, but + * reading less than MAX_TEXT characters works around + * the issue. + */ +#ifndef SIMULATE_CHARMODE + if ((ip->noecho & (CHARMODE_REQ|CHARMODE)) == (CHARMODE_REQ|CHARMODE)) +#else + if (ip->noecho & (CHARMODE_REQ|CHARMODE)) +#endif + { + l -= 2; + } + + DTN(("text_end %hd, can read %d chars\n", ip->text_end, l)); + #ifdef USE_TLS if (ip->tls_status != TLS_INACTIVE) - l = tls_read(ip, ip->text + ip->text_end, l); + l = tls_read(ip, ip->text + ip->text_end, (size_t)l); else #endif l = socket_read(ip->socket, ip->text + ip->text_end, (size_t)l); - + DTN(("# chars read: %d\n", l)); + /* TODO: Check if the block below can be simplified by using + * TODO::strerror().*/ if (l == -1) { if (errno == ENETUNREACH) { debug_message("%s Net unreachable detected.\n" @@ -3251,8 +3281,8 @@ get_message (char *buff, size_t *len) ? ip->tn_start : ip->command_end ) - ip->command_start; - DTN((" incomplete negotiation: length %d\n" - , length)); + DTN((" incomplete negotiation: length %ld\n" + , (long)length)); if (!length) continue; if (length < 0) @@ -3260,7 +3290,7 @@ get_message (char *buff, size_t *len) comm_fatal(ip, "comm: data length < 0: %ld\n", (long)length); continue; } - DTN((" save machine state %d, set to %d (READY)\n" + DTN((" save machine state %hhd, set to %d (READY)\n" , ip->tn_state, TS_READY)); ip->save_tn_state = ip->tn_state; ip->chars_ready = length; @@ -3274,7 +3304,7 @@ get_message (char *buff, size_t *len) * At the moment it is TS_INVALID, so the next * character received would be thrown away. */ - DTN((" save machine state %d (DATA)\n" + DTN((" Empty input: save machine state %d (DATA)\n" , TS_DATA)); length = strlen(ip->text + ip->command_start) + 1; ip->chars_ready = length; @@ -3286,7 +3316,7 @@ get_message (char *buff, size_t *len) /* Copy as many characters from the text[] into * the buff[] as possible. */ - DTN((" %ld chars ready\n", ip->chars_ready)); + DTN((" %"PRId32" chars ready\n", ip->chars_ready)); if (end_of_line) { DTN((" faking NL\n")); @@ -3337,7 +3367,7 @@ get_message (char *buff, size_t *len) if (!end_of_line) ip->chars_ready -= destix; - DTN((" %ld chars left ready\n", ip->chars_ready)); + DTN((" %"PRId32" chars left ready\n", ip->chars_ready)); if (!ip->chars_ready) { /* All the pure data was read, now restore the @@ -3345,7 +3375,7 @@ get_message (char *buff, size_t *len) * Leave the first char in to make input escape * possible */ - DTN((" restore old telnet machine state %d\n" + DTN((" restore old telnet machine state %hhd\n" , ip->save_tn_state)); ip->tn_state = ip->save_tn_state; ip->save_tn_state = TS_INVALID; @@ -3366,6 +3396,7 @@ get_message (char *buff, size_t *len) * negative. We have to correct them then to point * to ip->command_start. */ + DTN((" tn_start %hd, command_end %hd\n", ip->tn_start, ip->command_end)); if (ip->tn_start < 1) ip->tn_start = 1; if (ip->command_end < 1) @@ -3389,7 +3420,7 @@ get_message (char *buff, size_t *len) ip->numCmds++; #endif - DTN(("--- return with char command %02x '%c' ---\n", buff[0], buff[0])); + DTN(("--- return with char command %02x '%c' length %d ---\n", buff[0], buff[0], destix)); return MY_TRUE; } @@ -3400,7 +3431,7 @@ get_message (char *buff, size_t *len) ? ip->tn_start : ip->command_end ) - ip->command_start; - DTN((" data length %d\n", length)); + DTN((" data length %ld\n", (long)length)); if (length < 0) { comm_fatal(ip, "comm: data length < 0: %ld\n", (long)length); @@ -3430,7 +3461,7 @@ get_message (char *buff, size_t *len) * the beginning of .text[] and terminated with a '\0'. Whenever * a command is complete, the tn_state is TS_READY. */ - DTN(("tn complete, telnet machine state: %d\n", ip->tn_state)); + DTN(("tn complete, telnet machine state: %hhd\n", ip->tn_state)); if (ip->tn_state == TS_READY) { /* We have a command: copy it into buff, handle a @@ -3438,6 +3469,10 @@ get_message (char *buff, size_t *len) */ DTN(("telnet machine ready\n")); + /* buffer overflows here are impossible even with strcpy(), + * because buff is allocated in backend() as MAX_TEXT+4 and + * ip->text is allocated as MAX_TEXT+2. Ok, as long as nobody + * changes buff in backend() withour changing ip->text ... */ strcpy(buff, ip->text); command_giver = ip->ob; trace_level = ip->trace_level; @@ -3484,6 +3519,10 @@ get_message (char *buff, size_t *len) } else { + /* buff is limited to MAX_TEXT+4. Additionally, + * get_message() is usually not called recursively or + * from a very high stack depth, so alloca() is + * probably ok. */ char *snoop_message = alloca(strlen(buff) + 4); sprintf(snoop_message, "%% %s\n", buff); tell_npc_str(snooper, snoop_message); @@ -3794,9 +3833,9 @@ static void new_player ( object_t *ob, SOCKET_T new_socket , struct sockaddr_in *addr, size_t addrlen #if !defined(ACCESS_CONTROL) && !defined(USE_AUTHLOCAL) - , int login_port UNUSED + , int login_port UNUSED #else - , int login_port + , int login_port #endif ) @@ -3924,8 +3963,8 @@ new_player ( object_t *ob, SOCKET_T new_socket message = "Cannot accept connection (out of memory). Come back later.\r\n"; socket_write(new_socket, message, strlen(message)); socket_close(new_socket); - debug_message("%s Out of memory (%lu bytes) for new connection.\n" - , time_stamp(), (unsigned long) sizeof(interactive_t)); + debug_message("%s Out of memory (%zu bytes) for new connection.\n" + , time_stamp(), sizeof(interactive_t)); return; } @@ -4137,7 +4176,7 @@ new_player ( object_t *ob, SOCKET_T new_socket /*-------------------------------------------------------------------------*/ void -set_noecho (interactive_t *ip, char noecho, Bool local_change) +set_noecho (interactive_t *ip, char noecho, Bool local_change, Bool external) /* Change the input mode ->noecho to the given , performing all * necessary telnet negotiations. If the driverhook H_NOECHO is set, @@ -4152,7 +4191,7 @@ set_noecho (interactive_t *ip, char noecho, Bool local_change) if (!ip->tn_enabled) { - DTN(("set_noecho(%02x) old %02x: TN disabled\n" + DTN(("set_noecho(%02hhx) old %02hhx: TN disabled\n" , noecho, ip->noecho)); } @@ -4160,11 +4199,11 @@ set_noecho (interactive_t *ip, char noecho, Bool local_change) confirm = (char)( noecho | CHARMODE_REQ_TO_CHARMODE(noecho & (NOECHO_REQ|CHARMODE_REQ))); - DTN(("set_noecho(%02x%s) old %02x %s\n" + DTN(("set_noecho(%02hhx%s) old %02hhx %s\n" , noecho, local_change ? " local" : "", old, decode_noecho(old))); - DTN((" -> confirm: %02x %s\n" + DTN((" -> confirm: %02hhx %s\n" , confirm, decode_noecho(confirm))); - DTN((" -> %02x %s\n" + DTN((" -> %02hhx %s\n" , confirm | NOECHO_ACKSHIFT(confirm) , decode_noecho(confirm | NOECHO_ACKSHIFT(confirm)) )); @@ -4187,7 +4226,7 @@ set_noecho (interactive_t *ip, char noecho, Bool local_change) push_ref_valid_object(inter_sp, ob, "set_no_echo"); push_number(inter_sp, local_change ? 1 : 0); if (driver_hook[H_NOECHO].type == T_STRING) - secure_apply(driver_hook[H_NOECHO].u.str, ob, 3); + secure_apply_ob(driver_hook[H_NOECHO].u.str, ob, 3, external); else { if (driver_hook[H_NOECHO].x.closure_type == CLOSURE_LAMBDA) @@ -4197,14 +4236,14 @@ set_noecho (interactive_t *ip, char noecho, Bool local_change) driver_hook[H_NOECHO].u.lambda->ob = ref_object(ob, "set_noecho"); } - secure_callback_lambda(&driver_hook[H_NOECHO], 3); + secure_call_lambda(&driver_hook[H_NOECHO], 3, external); } if (~confirm & old & CHARMODE_MASK) { if (ip->save_tn_state != TS_INVALID) { DT(("'%s' set_noecho(): 0 chars ready, " - "saved state %d\n", get_txt(ip->ob->name) + "saved state %hhd\n", get_txt(ip->ob->name) , ip->save_tn_state)); ip->chars_ready = 0; ip->tn_state = ip->save_tn_state; @@ -4275,7 +4314,7 @@ set_noecho (interactive_t *ip, char noecho, Bool local_change) } if (ip->save_tn_state != TS_INVALID) { - DTN(("set_noecho(): 0 chars ready, saved state %d\n", ip->save_tn_state)); + DTN(("set_noecho(): 0 chars ready, saved state %hhd\n", ip->save_tn_state)); ip->chars_ready = 0; ip->tn_state = ip->save_tn_state; } @@ -4428,7 +4467,8 @@ call_function_interactive (interactive_t *i, char *str, size_t len) { /* Sorry, the object has selfdestructed ! */ set_noecho(i, it->next ? it->next->noecho : 0 - , it->next ? it->next->local : MY_FALSE); + , it->next ? it->next->local : MY_FALSE + , MY_TRUE); i->input_to = it->next; free_input_to(it); return MY_FALSE; @@ -4439,7 +4479,8 @@ call_function_interactive (interactive_t *i, char *str, size_t len) && load_ob_from_swap(ob) < 0) { set_noecho(i, it->next ? it->next->noecho : 0 - , it->next ? it->next->local : MY_FALSE); + , it->next ? it->next->local : MY_FALSE + , MY_TRUE); i->input_to = it->next; free_input_to(it); errorf("Out of memory: unswap object '%s'.\n", get_txt(ob->name)); @@ -4470,7 +4511,7 @@ call_function_interactive (interactive_t *i, char *str, size_t len) error_recovery_info.rt.last = rt_context; error_recovery_info.rt.type = ERROR_RECOVERY_BACKEND; - rt_context = (rt_context_t *)&error_recovery_info; + rt_context = (rt_context_t *)&error_recovery_info.rt; if (setjmp(error_recovery_info.con.text)) { @@ -4505,7 +4546,8 @@ call_function_interactive (interactive_t *i, char *str, size_t len) if (i->noecho & NOECHO_STALE) { set_noecho(i, i->input_to ? i->input_to->noecho : 0 - , i->input_to ? i->input_to->local : MY_FALSE); + , i->input_to ? i->input_to->local : MY_FALSE + , MY_TRUE); } /* Done */ @@ -4561,7 +4603,7 @@ set_call ( object_t *ob, input_to_t *it, char noecho ip->set_input_to = MY_TRUE; if (noecho || ip->noecho) - set_noecho(ip, noecho, local_change); + set_noecho(ip, noecho, local_change, MY_FALSE); return MY_TRUE; } /* set_call() */ @@ -4641,7 +4683,9 @@ print_prompt_string (string_t *prompt) put_number(hook, 0); current_object = NULL; /* So that catch_tell() can see it */ add_message(FMT_STRING, prompt); - errorf("H_PRINT_PROMPT for %s was a closure bound to a now-destructed object - hook removed.\n", get_txt(command_giver->name)); + errorf("H_PRINT_PROMPT for %s was a closure bound to a " + "now-destructed object - hook removed.\n", + get_txt(command_giver->name)); /* NOTREACHED */ } @@ -4725,7 +4769,9 @@ print_prompt (void) free_svalue(prompt); put_ref_string(prompt, STR_DEFAULT_PROMPT); print_prompt_string(prompt->u.str); - errorf("Prompt of %s was a closure bound to a now-destructed object - default prompt restored.\n", get_txt(command_giver->name)); + errorf("Prompt of %s was a closure bound to a now-destructed " + "object - default prompt restored.\n", + get_txt(command_giver->name)); /* NOTREACHED */ } @@ -5096,7 +5142,7 @@ reply_to_will_sga (int option) send_do(option); } else DTN((" we don't need to say DO\n")); - DTN((" noecho: %02x -> %02x\n", ip->noecho, (char)(ip->noecho | CHARMODE_MASK))); + DTN((" noecho: %02hhx -> %02hhx\n", ip->noecho, (char)(ip->noecho | CHARMODE_MASK))); ip->noecho |= CHARMODE_MASK; } else { send_dont(option); @@ -5134,7 +5180,8 @@ reply_to_wont_sga (int option) send_dont(option); } else DTN((" we don't need to say DONT\n")); - DTN((" noecho: %02x -> %02x\n", ip->noecho, (unsigned char)((ip->noecho & ~CHARMODE) | CHARMODE_ACK))); + DTN((" noecho: %02hhx -> %02hhx\n", ip->noecho, + (unsigned char)((ip->noecho & ~CHARMODE) | CHARMODE_ACK))); ip->noecho = (char)((ip->noecho & ~CHARMODE) | CHARMODE_ACK); /* Don't reset CHARMODE_REQ here: this WONT can be the answer * to the DO SGA we sent before, and the client can still answer @@ -5176,7 +5223,7 @@ mccp_telnet_neg (int option) #endif break; default: - DTF(("MCCP NEG (%d) STATE (%d)\n", option, ip->tn_state)); + DTF(("MCCP NEG (%d) STATE (%hhd)\n", option, ip->tn_state)); } } /* mccp_telnet_neg() */ @@ -5248,7 +5295,7 @@ reply_h_telnet_neg (int option) i = WONT; break; default: - debug_message("%s Invalid tn_state %d for interactive '%s'\n" + debug_message("%s Invalid tn_state %hhd for interactive '%s'\n" , time_stamp(), ip->tn_state, get_txt(ip->ob->name)); break; } @@ -5498,7 +5545,7 @@ telnet_neg (interactive_t *ip) from = &first[ip->tn_end]; end = &first[ip->text_end]; - DTN(("telnet_neg: state %d\n", ip->tn_state)); + DTN(("telnet_neg: state %hhd\n", ip->tn_state)); /* Gobble the character *from if gobble_char is set. * Also test for the end of current buffer content. @@ -5516,7 +5563,7 @@ telnet_neg (interactive_t *ip) return; } if (ip->gobble_char) { - DTN(("t_n: gobble char %02x (in buf: %02x)\n" + DTN(("t_n: gobble char %02hhx (in buf: %02x)\n" , ip->gobble_char, *from)); /* we had a crash around here: * @@ -5585,7 +5632,7 @@ $12 = 0x2acc67ca
do { ch = (*from++ & 0xff); - DTN(("t_n: processing %02x '%c'\n" + DTN(("t_n: processing %02hhx '%c'\n" , (unsigned char)ch, ch)); switch(ip->tn_state) { @@ -5601,6 +5648,8 @@ $12 = 0x2acc67ca
if (from >= end) { ip->text_end = ip->tn_end = ip->command_end = (short)(to - first); + DTN(("t_n: (ts_data) from >= end by %td, text_end := %hd\n (max %d)" + , (ptrdiff_t)(from-end), ip->text_end, MAX_TEXT)); *to = '\0'; if (ip->text_end >= MAX_TEXT) { @@ -5610,16 +5659,19 @@ $12 = 0x2acc67ca
* In charmode, we must not reset command_end, otherwise * it might fall under command_start. */ - ip->text_end = ip->tn_end = 0; - if (!(ip->noecho & CHARMODE_REQ)) - ip->command_end = 0; ip->tn_state = TS_READY; + ip->tn_end = 0; + ip->text_end = 0; + if (!(ip->noecho & (CHARMODE_REQ|CHARMODE))) + { + ip->command_end = 0; + } return; } return; } ch = (*from++ & 0xff); - DTN(("t_n: (ts_data) processing %02x '%c'\n" + DTN(("t_n: (ts_data) processing %02hhx '%c'\n" , (unsigned char)ch, ch)); /* FALLTHROUGH */ @@ -5831,7 +5883,7 @@ $12 = 0x2acc67ca
case GA: DTN(("t_n: got GA\n")); break; default: - DTN(("t_n: got %02x\n", ch)); break; + DTN(("t_n: got %02hhx\n", ch)); break; break; } /* switch(ch) */ state = ip->ts_data; @@ -5840,7 +5892,7 @@ $12 = 0x2acc67ca
case TS_WILL: command_giver = ip->ob; if (ch < NTELOPTS) { - DTN(("t_n: state WILL got %s (%02x)\n" + DTN(("t_n: state WILL got %s (%02hhx)\n" , telopts[ch], ch)); #ifdef DEBUG_TELNET if (d_flag) @@ -5848,7 +5900,7 @@ $12 = 0x2acc67ca
#endif (*telopts_will[ch])(ch); } else { - debug_message("%s Unknown telnet option Will %d\n" + debug_message("%s Unknown telnet option Will %hhd\n" , time_stamp(), ch); send_dont(ch); } @@ -5858,7 +5910,7 @@ $12 = 0x2acc67ca
case TS_WONT: command_giver = ip->ob; if (ch < NTELOPTS) { - DTN(("t_n: state WONT got %s (%02x)\n" + DTN(("t_n: state WONT got %s (%02hhx)\n" , telopts[ch], ch)); #ifdef DEBUG_TELNET if (d_flag) @@ -5866,7 +5918,7 @@ $12 = 0x2acc67ca
#endif (*telopts_wont[ch])(ch); } else { - debug_message("%s Unknown telnet option Wont %d\n" + debug_message("%s Unknown telnet option Wont %hhd\n" , time_stamp(), ch); } state = ip->ts_data; @@ -5875,7 +5927,7 @@ $12 = 0x2acc67ca
case TS_DO: command_giver = ip->ob; if (ch < NTELOPTS) { - DTN(("t_n: state DO got %s (%02x)\n" + DTN(("t_n: state DO got %s (%02hhx)\n" , telopts[ch], ch)); #ifdef DEBUG_TELNET if (d_flag) @@ -5883,7 +5935,7 @@ $12 = 0x2acc67ca
#endif (*telopts_do[ch])(ch); } else { - debug_message("%s Unknown telnet option Do %d\n" + debug_message("%s Unknown telnet option Do %hhd\n" , time_stamp(), ch); send_wont(ch); } @@ -5893,7 +5945,7 @@ $12 = 0x2acc67ca
case TS_DONT: command_giver = ip->ob; if (ch < NTELOPTS) { - DTN(("t_n: state DONT got %s (%02x)\n" + DTN(("t_n: state DONT got %s (%02hhx)\n" , telopts[ch], ch)); #ifdef DEBUG_TELNET if (d_flag) @@ -5901,14 +5953,14 @@ $12 = 0x2acc67ca
#endif (*telopts_dont[ch])(ch); } else { - debug_message("%s Unknown telnet option Dont %d\n" + debug_message("%s Unknown telnet option Dont %hhd\n" , time_stamp(), ch); } state = ip->ts_data; goto change_state; case TS_SB: - DTN(("t_n: state TS_SB got %02x\n", ch)); + DTN(("t_n: state TS_SB got %02hhx\n", ch)); if (ch == IAC) { state = TS_SB_IAC; goto change_state; @@ -5921,7 +5973,7 @@ $12 = 0x2acc67ca
mp_int size; vector_t *v; - DTN(("t_n: state TS_SB_IAC got %02x\n", ch)); + DTN(("t_n: state TS_SB_IAC got %02hhx\n", ch)); if (ch == IAC) { DTN(("t_n: that is: state TS_SB_IAC got IAC\n")); *to++ = (char)ch; @@ -5937,7 +5989,7 @@ $12 = 0x2acc67ca
svalue_t *svp; str = (unsigned char *)&ip->text[ip->tn_start]; - DTN(("t_n: that is: state TS_SB_IAC got useful SE or SB: neg SB %02x (%ld bytes)\n", *str, size)); + DTN(("t_n: that is: state TS_SB_IAC got useful SE or SB: neg SB %02hhx (%"PRIdMPINT" bytes)\n", *str, size)); push_number(inter_sp, SB); push_number(inter_sp, *str++); svp = v->item; @@ -5957,7 +6009,7 @@ $12 = 0x2acc67ca
} case TS_SYNCH: - DTN(("t_n: state TS_SYNCH got %02x\n", ch)); + DTN(("t_n: state TS_SYNCH got %02hhx\n", ch)); if (ch == IAC) goto new_iac; if (ch == DM) goto data_mark; continue; @@ -5965,7 +6017,7 @@ $12 = 0x2acc67ca
default: #ifdef DEBUG_TELNET if (d_flag) - debug_message("%s Bad state: 0x%x\n", time_stamp(), ip->tn_state); + debug_message("%s Bad state: 0x%hhx\n", time_stamp(), ip->tn_state); #endif state = TS_DATA; goto change_state; @@ -6349,13 +6401,17 @@ f_send_erq (svalue_t *sp) vector_t *v; svalue_t *svp; char *cp; - mp_int j; + p_int j; v = sp[-1].u.vec; arglen = VEC_SIZE(v); - cp = arg = alloca(arglen); + cp = arg = xalloc(arglen); + if (!arg) { + errorf("Out of memory (%zu bytes) in send_erq() for allocating " + "temporary buffer.\n", arglen); + } svp = &v->item[0]; - for (j = (mp_int)arglen; --j >= 0; ) + for (j = (p_int)arglen; --j >= 0; ) *cp++ = (char)(*svp++).u.number; } @@ -6403,7 +6459,11 @@ failure: i = 0; free_svalue(sp); } - + /* cleanup */ + if (sp[-1].type != T_STRING) { + /* free arg only if sp-1 is not a string */ + xfree(arg); + } free_svalue(--sp); (*--sp).u.number = i; @@ -6564,7 +6624,7 @@ open_ipv6_conn( const char *hostname, const unsigned short int port h = gethostbyname2(hostname, AF_INET); if(h) { - CREATE_IPV6_MAPPED(addr.sin6_addr, *((u_int32_t *)h->h_addr_list[0])); + CREATE_IPV6_MAPPED(&addr.sin6_addr, *((u_int32_t *)h->h_addr_list[0])); con = connect(sock, (struct sockaddr *) &addr, sizeof(addr)); } } @@ -6688,7 +6748,8 @@ remove_stale_player_data (void) { set_noecho(all_players[i] , it->next ? it->next->noecho : 0 - , it->next ? it->next->local : MY_FALSE); + , it->next ? it->next->local : MY_FALSE + , MY_TRUE); all_players[i]->input_to = it->next; } else @@ -6781,7 +6842,7 @@ show_comm_status (strbuf_t * sbuf, Bool verbose UNUSED) } if (sbuf) - strbuf_addf(sbuf, "Comm structures\t\t\t\t %9lu\n", sum); + strbuf_addf(sbuf, "Comm structures\t\t\t\t %9zu\n", sum); return sum; } /* show_comm_status() */ @@ -7212,7 +7273,7 @@ f_send_udp (svalue_t *sp) */ { - char *to_host; + char *to_host = NULL; int to_port; char *msg; size_t msglen; @@ -7222,7 +7283,10 @@ f_send_udp (svalue_t *sp) struct sockaddr_in name; struct hostent *hp; int ret = 0; - + svalue_t *firstarg; /* store the first argument */ + + firstarg = sp-2; /* hostname */ + switch(0) { default: /* try {...} */ /* Set msg/msglen to the data of the message to send */ @@ -7237,21 +7301,26 @@ f_send_udp (svalue_t *sp) vector_t *v; svalue_t *svp; char *cp; - mp_int j; + p_int j; v = sp->u.vec; msglen = VEC_SIZE(v); - cp = msg = alloca(msglen); - if (!msg) - break; + /* allocate memory and push error handler onto stack */ + cp = msg = xalloc_with_error_handler(msglen); + if (!msg) { + errorf("Out of memory (%zu bytes) in send_udp() for " + "temporary buffer.\n", msglen); + } + sp = inter_sp; + svp = &v->item[0]; - for (j = (mp_int)msglen; --j >= 0; ) + for (j = (p_int)msglen; --j >= 0; ) *cp++ = (char)(*svp++).u.number; } /* Is this call valid? */ - if (!privilege_violation(STR_SEND_UDP, sp-2, sp)) + if (!privilege_violation(STR_SEND_UDP, firstarg, firstarg + 2)) break; if (udp_s < 0) @@ -7262,16 +7331,17 @@ f_send_udp (svalue_t *sp) { size_t adrlen; - adrlen = mstrsize((sp-2)->u.str); - to_host = alloca(adrlen+1); + adrlen = mstrsize(firstarg->u.str); + /* as there are no runtime error raised below, we just xallocate + * and don't bother with an error handler. */ + to_host = xalloc(adrlen+1); if (!to_host) { - inter_sp = sp; - errorf("Out of stack (%lu bytes) for host address\n" - , (unsigned long)(adrlen+1)); + errorf("Out of memory (%zu bytes) in send_udp() for host address\n" + , (adrlen+1)); /* NOTREACHED */ } - memcpy(to_host, get_txt((sp-2)->u.str), adrlen); + memcpy(to_host, get_txt(firstarg->u.str), adrlen); to_host[adrlen] = '\0'; } to_port = (sp-1)->u.number; @@ -7302,7 +7372,7 @@ f_send_udp (svalue_t *sp) if (hp->h_addrtype == AF_INET) { - CREATE_IPV6_MAPPED(name.sin_addr, (u_int32_t)hp->h_addr_list[0]); + CREATE_IPV6_MAPPED(&name.sin_addr, (u_int32_t)hp->h_addr_list[0]); } name.sin_family = AF_INET6; #endif /* USE_IPV6 */ @@ -7317,14 +7387,18 @@ f_send_udp (svalue_t *sp) break; ret = 1; } - - /* Return the result */ - - free_svalue(sp); - free_svalue(--sp); - free_svalue(--sp); + /* Cleanup - an allocated buffer for the message will be on the stack + * above the arguments, therefore clean everything from the first argument + * (including) to sp. + */ + sp = pop_n_elems((sp-firstarg)+1, sp); + xfree(to_host); + + /*Return the result */ + sp++; put_number(sp, ret); return sp; + } /* f_send_udp() */ /*-------------------------------------------------------------------------*/ @@ -7350,7 +7424,7 @@ f_set_buffer_size (svalue_t *sp) if (sp->u.number > SET_BUFFER_SIZE_MAX) { - errorf("Bad arg 1 to set_buffer_size(): value %ld exceeds maximum %ld\n" + errorf("Bad arg 1 to set_buffer_size(): value %"PRIdPINT" exceeds maximum %ld\n" , sp->u.number, (long) SET_BUFFER_SIZE_MAX); /* NOTREACHED */ return sp; @@ -7437,7 +7511,7 @@ f_binary_message (svalue_t *sp) size = VEC_SIZE(sp[-1].u.vec); msg = alloc_mstring(size); if (!msg) - fatal("Stack overflow in binary_message()"); + errorf("Out of memory (%zu bytes) in binary_message()",size); for (i = (mp_int)size, svp = sp[-1].u.vec->item, p = get_txt(msg) ; --i >= 0; svp++) { @@ -7515,6 +7589,7 @@ f_binary_message (svalue_t *sp) } if (wrote == -1) { + /* TODO: Use strerror()? */ switch(errno) { case EINTR: @@ -7827,7 +7902,7 @@ v_input_to (svalue_t *sp, int num_arg) if (arg[2].type != T_STRING && arg[2].type != T_CLOSURE) { - vefun_bad_arg(3, arg-1); + vefun_bad_arg(3, sp); /* NOTREACHED */ } } @@ -7896,7 +7971,7 @@ v_input_to (svalue_t *sp, int num_arg) if (error_index >= 0) { free_input_to(it); - vefun_bad_arg(error_index, arg-1); + vefun_bad_arg(error_index + num_arg - extra + 1, arg-1); /* NOTREACHED */ return arg-1; } @@ -8081,6 +8156,7 @@ v_find_input_to (svalue_t *sp, int num_arg) break; default: + /* TODO: Wouldn't errorf() suffice? */ fatal("Unsupported argument type %d\n", arg[1].type); break; } @@ -8235,6 +8311,7 @@ v_remove_input_to (svalue_t *sp, int num_arg) break; default: + /* TODO: Wouldn't errorf() suffice? */ fatal("Unsupported argument type %d\n", arg[1].type); break; } @@ -8270,6 +8347,7 @@ v_remove_input_to (svalue_t *sp, int num_arg) ip->noecho |= NOECHO_STALE; set_noecho(ip, ip->input_to ? ip->input_to->noecho : ip->noecho , ip->input_to ? ip->input_to->local : MY_FALSE + , MY_FALSE ); } @@ -8469,7 +8547,7 @@ f_query_mud_port (svalue_t *sp) { if (sp->u.number < -1 || sp->u.number >= numports) { - errorf("Bad arg 1 to query_mud_port(): value %ld out of range.\n" + errorf("Bad arg 1 to query_mud_port(): value %"PRIdPINT" out of range.\n" , sp->u.number); /* NOTREACHED */ } @@ -8491,6 +8569,15 @@ f_query_mud_port (svalue_t *sp) } /* f_query_mud_port() */ /*-------------------------------------------------------------------------*/ + + +static inline void translate_bit(char c, int i, int length, string_t *rc, unsigned int bitno) +/* static helper function to translatin bits to characters in get_charset */ +{ + if (c & (1 << bitno)) + get_txt(rc)[length++] = (char)(i * 8 + bitno); +} /* translate_bit */ + static void get_charset (svalue_t * sp, p_int mode, char charset[32]) @@ -8504,7 +8591,7 @@ get_charset (svalue_t * sp, p_int mode, char charset[32]) switch (mode) { default: - fatal("(get_charset): Illegal mode value %ld\n", mode); + fatal("(get_charset): Illegal mode value %"PRIdPINT"\n", mode); /* NOTREACHED */ break; @@ -8560,19 +8647,14 @@ get_charset (svalue_t * sp, p_int mode, char charset[32]) { char c = charset[i]; -#define TRANSLATE(bitno) \ - if (c & (1 << bitno)) \ - get_txt(rc)[length++] = (char)(i * 8 + bitno); - - TRANSLATE(0); - TRANSLATE(1); - TRANSLATE(2); - TRANSLATE(3); - TRANSLATE(4); - TRANSLATE(5); - TRANSLATE(6); - TRANSLATE(7); -#undef TRANSLATE + translate_bit(c, i, length, rc, 0); + translate_bit(c, i, length, rc, 1); + translate_bit(c, i, length, rc, 2); + translate_bit(c, i, length, rc, 3); + translate_bit(c, i, length, rc, 4); + translate_bit(c, i, length, rc, 5); + translate_bit(c, i, length, rc, 6); + translate_bit(c, i, length, rc, 7); } put_string(sp, rc); @@ -8608,9 +8690,9 @@ f_get_combine_charset (svalue_t *sp) mode = sp->u.number; if (mode != CHARSET_VECTOR && mode != CHARSET_STRING) { - errorf("Bad arg 1 to get_combine_charset(): %ld, " + errorf("Bad arg 1 to get_combine_charset(): %"PRIdPINT", " "expected CHARSET_VECTOR (%d) or CHARSET_STRING (%d)\n" - , (long) mode, CHARSET_VECTOR, CHARSET_STRING); + , mode, CHARSET_VECTOR, CHARSET_STRING); /* NOTREACHED */ return sp; } @@ -8659,8 +8741,8 @@ f_set_combine_charset (svalue_t *sp) i = 0; if (sp->type == T_POINTER && (i = (mp_int)VEC_SIZE(sp->u.vec)) > 32) { - errorf("Bad arg 1 to set_combine_charset(): int[] too long (%ld)\n" - , (long)i); + errorf("Bad arg 1 to set_combine_charset(): int[] too long (%"PRIdMPINT")\n" + , i); /* NOTREACHED */ return sp; } @@ -8732,10 +8814,10 @@ f_get_connection_charset (svalue_t *sp) if (mode != CHARSET_VECTOR && mode != CHARSET_STRING && mode != CHARSET_QUOTE_IAC) { - errorf("Bad arg 1 to get_connection_charset(): %ld, " + errorf("Bad arg 1 to get_connection_charset(): %"PRIdPINT", " "expected CHARSET_VECTOR (%d), _STRING (%d), " "or _QUOTE_IAC (%d)\n" - , (long) mode, CHARSET_VECTOR, CHARSET_STRING, CHARSET_QUOTE_IAC); + , mode, CHARSET_VECTOR, CHARSET_STRING, CHARSET_QUOTE_IAC); /* NOTREACHED */ return sp; } @@ -8791,8 +8873,8 @@ f_set_connection_charset (svalue_t *sp) i = 0; if (sp[-1].type == T_POINTER && (i = (mp_int)VEC_SIZE(sp[-1].u.vec)) > 32) { - errorf("Bad arg 1 to set_connection_charset(): array too big (%ld)\n" - , i); + errorf("Bad arg 1 to set_connection_charset(): array too big (%" + PRIdMPINT")\n", i); /* NOTREACHED */ return sp; } @@ -8892,8 +8974,8 @@ f_set_prompt (svalue_t *sp) if (!str) { inter_sp = sp; - errorf("(set_prompt) Out of memory (%lu bytes) for prompt\n" - , (unsigned long) mstrsize(sp->u.str)); + errorf("(set_prompt) Out of memory (%zu bytes) for prompt\n" + , mstrsize(sp->u.str)); } else { @@ -8915,7 +8997,7 @@ f_set_prompt (svalue_t *sp) assign_svalue(sp, prompt); else { - errorf("Bad int arg 1 to set_prompt(): got %ld, expected 0 or -1.\n" + errorf("Bad int arg 1 to set_prompt(): got %"PRIdPINT", expected 0 or -1.\n" , sp->u.number); /* NOTREACHED */ return sp; @@ -9151,7 +9233,7 @@ f_enable_telnet (svalue_t *sp) put_number(sp, rc); return sp; } /* f_enable_telnet() */ - + /*-------------------------------------------------------------------------*/ #ifdef USE_EXPERIMENTAL svalue_t * diff --git a/src/comm.h b/src/comm.h index c441001..b407049 100644 --- a/src/comm.h +++ b/src/comm.h @@ -156,6 +156,10 @@ struct input_to_s { * * When changing struct members, take care that you don't introduce * unnecessary padding. + * + * If the CBool members should ever be changed to C99's _Bool, take care of + * checking who is relying on a specific size (e.g. some printf()) + * */ struct interactive_s { @@ -416,7 +420,7 @@ extern void add_message VARPROT((const char *, ...), printf, 1, 2); extern void flush_all_player_mess(void); extern Bool get_message(char *buff, size_t *len); extern void remove_interactive(object_t *ob, Bool force); -extern void set_noecho(interactive_t *i, char noecho, Bool local_change); +extern void set_noecho(interactive_t *i, char noecho, Bool local_change, Bool external); extern int find_no_bang (interactive_t *ip); extern Bool call_function_interactive(interactive_t *i, char *str, size_t len); extern void remove_all_players(void); diff --git a/src/driver.h b/src/driver.h index 553ffef..e144700 100644 --- a/src/driver.h +++ b/src/driver.h @@ -14,6 +14,9 @@ #include "config.h" +/* Include the portability headers */ +#include "port.h" + /* TODO: Some TODO defines */ /* NO_NEGATIVE_RANGES: If defined, assignments to negative ranges @@ -46,17 +49,26 @@ # define GC_SUPPORT 1 #endif + /* Do some of the selected packages require special treatment? */ -/* SQLite in the threadsafe mode needs a normal malloc() */ -#if defined(SBRK_OK) && defined(USE_SQLITE) -# undef SBRK_OK -#endif +/* ptmalloc only works correctly with SBRK_OK right now. */ +#ifdef MALLOC_ptmalloc +# ifndef SBRK_OK +# define SBRK_OK +# endif +#else // no ptmalloc +/* SQLite in the threadsafe mode needs a normal malloc() if the allocator is + * not ptmalloc*/ +# if defined(SBRK_OK) && defined(USE_SQLITE) && defined(SQLITE3_USES_PTHREADS) +# undef SBRK_OK +# endif +/* PTHREADS need a normal malloc() if the allocator is not ptmalloc */ +# if defined(SBRK_OK) && defined(USE_PTHREADS) +# undef SBRK_OK +# endif +#endif // MALLOC_ptmalloc -/* PTHREADS need a normal malloc() */ -#if defined(SBRK_OK) && (defined(USE_PTHREADS) || defined(SQLITE3_USES_PTHREADS)) -# undef SBRK_OK -#endif /* When we have allocation tracing, the allocator annotates every * allocation with the source filename and line where the allocation @@ -131,9 +143,6 @@ # define __IPV6__ #endif -/* Include the portability headers */ -#include "port.h" - /* TODO: this ctype-stuff might go into lex.h (impl in efun_defs.c) */ #define _MCTe 0x01 /* escaped character in save/restore object. */ #define _MCTd 0x02 /* numeric digit */ @@ -166,4 +175,10 @@ extern unsigned char _my_ctype[]; #define MIN(a,b) (((a)<(b))?(a):(b)) #endif /* MIN */ +/* For the use of mudlib/sys/debug_info.h. + */ +#ifdef EVAL_COST_TRACE +#define __EVAL_COST_TRACE__ +#endif + #endif /* DRIVER_H__ */ diff --git a/src/dumpstat.c b/src/dumpstat.c index 1e93bd9..17c8ec7 100644 --- a/src/dumpstat.c +++ b/src/dumpstat.c @@ -346,7 +346,7 @@ dumpstat (string_t *fname) overhead += sizeof (object_t); - fprintf(f, "%-20s %5ld (%5ld) ref %2ld %s " + fprintf(f, "%-20s %5"PRIdMPINT" (%5"PRIdMPINT") ref %2"PRIdPINT" %s " , get_txt(ob->name) , compsize + overhead, totalsize + overhead , ob->ref @@ -360,14 +360,15 @@ dumpstat (string_t *fname) fprintf(f, "-- "); if (ob->gigaticks) - fprintf(f, " (%lu%09lu)", ob->gigaticks, ob->ticks); + fprintf(f, " (%"PRIuMPINT"%09"PRIuMPINT")", + (mp_uint)ob->gigaticks, (mp_uint)ob->ticks); else - fprintf(f, " (%lu)", ob->ticks); + fprintf(f, " (%"PRIuMPINT")", (mp_uint)ob->ticks); fprintf(f, " %s", swapstrings[(O_PROG_SWAPPED(ob)?1:0) | (O_VAR_SWAPPED(ob)?2:0)] ); tm = localtime((time_t *)&ob->load_time); - strftime(timest, sizeof(timest)-1, "%Y.%m.%d-%H:%M:%S", tm); + strftime(timest, sizeof(timest), "%Y.%m.%d-%H:%M:%S", tm); fprintf(f, " %s\n", timest); } fclose(f); @@ -406,7 +407,7 @@ dumpstat_dest(string_t *fname) if (!(ob->flags & O_DESTRUCTED)) /* TODO: Can't happen */ continue; #endif - fprintf(f, "%-20s ref %2ld NEW\n" + fprintf(f, "%-20s ref %2"PRIdPINT" NEW\n" , get_txt(ob->name) , ob->ref ); @@ -418,7 +419,7 @@ dumpstat_dest(string_t *fname) if (!(ob->flags & O_DESTRUCTED)) /* TODO: Can't happen */ continue; #endif - fprintf(f, "%-20s ref %2ld\n" + fprintf(f, "%-20s ref %2"PRIdPINT"\n" , get_txt(ob->name) , ob->ref ); diff --git a/src/ed.c b/src/ed.c index 3c19a85..90181d9 100644 --- a/src/ed.c +++ b/src/ed.c @@ -362,7 +362,7 @@ static void count_blanks(int line); static void _count_blanks(char *str, int blanks); static LINE *getptr(int num); static void putcntl(char c); -static void prntln(char *str, int vflg, int lin); +static void prntln(char *str, Bool vflg, int lin); static regexp_t *optpat(void); /*-------------------------------------------------------------------------*/ @@ -2917,6 +2917,7 @@ docmd (Bool glob) free_mstring(fptr); return err; } + free_mstring(fptr); P_FCHANGED = TRUE; break; @@ -3257,8 +3258,12 @@ clear_ed_buffer_refs (ed_buffer_t *b) { object_t *ob; + if (b->fname) + clear_string_ref(b->fname); + if (b->exit_fn) { + clear_string_ref(b->exit_fn); if ( NULL != (ob = b->exit_ob) ) { if (ob->flags & O_DESTRUCTED) diff --git a/src/efuns.c b/src/efuns.c index bfe633f..d3f371e 100644 --- a/src/efuns.c +++ b/src/efuns.c @@ -110,6 +110,7 @@ #include "comm.h" #include "dumpstat.h" #include "exec.h" +#include "gcollect.h" #include "heartbeat.h" #include "interpret.h" #include "lex.h" @@ -137,6 +138,8 @@ #include "wiz_list.h" #include "xalloc.h" +#include "i-eval_cost.h" + #include "../mudlib/sys/debug_info.h" #include "../mudlib/sys/driver_hook.h" #include "../mudlib/sys/objectinfo.h" @@ -144,6 +147,11 @@ #include "../mudlib/sys/strings.h" #include "../mudlib/sys/time.h" +/* Variables */ +string_t *last_ctime_result = NULL; + /* points to the result of the last f_ctime() call. If the caller asks for + * the same timestamp, it will be returned. */ + /* Forward declarations */ static void copy_svalue (svalue_t *dest, svalue_t *, struct pointer_table *, int); @@ -424,12 +432,20 @@ v_md5 (svalue_t *sp, int num_arg) if (iterations < 1) { - errorf("Bad argument 2 to md5(): expected a number > 0, but got %ld\n" - , (long) iterations); + errorf("Bad argument 2 to md5(): expected a number > 0, but got %" + PRIdPINT"\n", iterations); /* NOTREACHED */ return sp; } + if (add_eval_cost_n(10, iterations)) + { + free_svalue(sp); + put_number(sp, 0); + + // The interpreter loop will catch the exceeded evaluation cost. + return sp; + } if (sp->type == T_POINTER) { @@ -569,13 +585,20 @@ v_sha1 (svalue_t *sp, int num_arg) if (iterations < 1) { - errorf("Bad argument 2 to md5(): expected a number > 0, but got %ld\n" - , (long) iterations); + errorf("Bad argument 2 to sha1(): expected a number > 0, but got %" + PRIdPINT"\n", iterations); /* NOTREACHED */ return sp; } + if (add_eval_cost_n(10, iterations)) + { + free_svalue(sp); + put_number(sp, 0); + /* The interpreter loop will catch the exceeded evaluation cost. */ + return sp; + } if (sp->type == T_POINTER) { @@ -676,7 +699,7 @@ f_regexp (svalue_t *sp) string_t * pattern; /* The pattern passed in */ int opt; /* The RE options passed in */ int rc; /* Resultcode from the rx_exec() call */ - mp_int i; + mp_int i, j; v = (sp-2)->u.vec; pattern = (sp-1)->u.str; @@ -700,16 +723,18 @@ f_regexp (svalue_t *sp) /* Check every string in if it matches and set res[] * accordingly. + * Allocate memory and push error handler on the stack. */ - res = alloca(v_size * sizeof(*res)); + res = xalloc_with_error_handler(v_size * sizeof(*res)); if (!res) { free_regexp(reg); - inter_sp = sp; - errorf("Stack overflow in regexp()"); + errorf("Out of memory (%"PRIdMPINT" bytes) in regexp()", + v_size * sizeof(*res)); /* NOTREACHED */ return sp; } + sp = inter_sp; for (num_match = i = 0; i < v_size; i++) { string_t *line; @@ -719,8 +744,14 @@ f_regexp (svalue_t *sp) if (v->item[i].type != T_STRING) continue; - eval_cost++; - total_evalcost++; + if (add_eval_cost(1)) + { + /* Evalution cost exceeded: we abort matching at this point + * and let the interpreter detect the exception. + */ + break; + } + line = v->item[i].u.str; rc = rx_exec(reg, line, 0); if (rc == 0) @@ -729,7 +760,6 @@ f_regexp (svalue_t *sp) { const char * emsg = rx_error_message(rc, reg); free_regexp(reg); - inter_sp = sp; errorf("regexp: %s\n", emsg); /* NOTREACHED */ return NULL; @@ -741,15 +771,16 @@ f_regexp (svalue_t *sp) /* Create the result vector and copy the matching lines */ ret = allocate_array(num_match); - for (num_match=i=0; i < v_size; i++) { + for (j=i=0; i < v_size && j < num_match; i++) { if (!res[i]) continue; - assign_svalue_no_free(&ret->item[num_match], &v->item[i]); - num_match++; + assign_svalue_no_free(&ret->item[j++], &v->item[i]); } - + /* Free regexp and the intermediate buffer res by freeing the error + * handler. */ free_regexp(reg); - }while(0); + free_svalue(sp--); + } while(0); free_svalue(sp--); free_svalue(sp--); @@ -763,6 +794,43 @@ f_regexp (svalue_t *sp) } /* f_regexp() */ /*-------------------------------------------------------------------------*/ +/* The found delimiter matches in f_regexplode() are kept in a list of these + * structures. + */ +struct regexplode_match { + size_t start, end; /* Start and end of the match in text */ + struct regexplode_match *next; /* Next list element */ +}; + +/* We need a special error handling for f_reg_explode(). It allocates a + * chained list of regexplode_match structures in a mempool and the compiled + * regexp which we have to free. + */ +struct regexplode_cleanup_s { + svalue_t sval; + regexp_t *reg; + Mempool matchmempool; +}; + +static void +regexplode_error_handler( svalue_t * arg) +/* The error handler: delete the mempool and free the compiled regexp. + * Note: it is static, but the compiler will have to emit a function and + * symbol for this because the address of the function is taken and it is + * therefore not suitable to be inlined. + */ +{ + struct regexplode_cleanup_s *handler = (struct regexplode_cleanup_s *)arg; + + if (handler->reg) + free_regexp(handler->reg); + + if (handler->matchmempool) { + mempool_delete(handler->matchmempool); + } + xfree(handler); +} /* regexplode_error_handler() */ + svalue_t * f_regexplode (svalue_t *sp) @@ -779,13 +847,6 @@ f_regexplode (svalue_t *sp) */ { - /* The found delimiter matches are kept in a list of these - * structures which are allocated on the stack. - */ - struct regexplode_match { - size_t start, end; /* Start and end of the match in text */ - struct regexplode_match *next; /* Next list element */ - }; string_t *text; /* Input string */ string_t *pattern; /* Delimiter pattern from the vm stack */ @@ -796,25 +857,47 @@ f_regexplode (svalue_t *sp) vector_t *ret; /* Result vector */ svalue_t *svp; /* Next element in ret to fill in */ int num_match; /* Number of matches */ - int arraysize; /* Size of result array */ + p_int arraysize; /* Size of result array */ int opt; /* RE options */ int rc; /* Result from rx_exec() */ size_t start; /* Start position for match */ + Mempool pool; /* Mempool for the list of matches */ + /* cleanup structure holding the head of chain of matches */ + struct regexplode_cleanup_s *cleanup; + /* Get the efun arguments */ - text = sp[-2].u.str; pattern = sp[-1].u.str; opt = (int)sp->u.number; + + /* allocate space for cleanup structure. */ + cleanup = xalloc(sizeof(*cleanup)); + if (!cleanup) + errorf("Out of memory (%zu bytes) for cleanup structure in " + "regexplode().\n",sizeof(*cleanup)); + /* create mempool */ + pool = new_mempool(size_mempool(sizeof(*matches))); + if (!pool) + { + xfree(cleanup); + errorf("Out of memory (%zu) for mempool in regexplode().\n", + sizeof(*matches)); + } + cleanup->matchmempool = pool; + cleanup->reg = NULL; + /* push error handler above the args on the stack */ + sp = push_error_handler(regexplode_error_handler, &(cleanup->sval)); + reg = rx_compile(pattern, opt, MY_FALSE); if (reg == 0) { - inter_sp = sp; errorf("Unrecognized search pattern"); /* NOTREACHED */ return sp; } - + cleanup->reg = reg; + /* Loop over , repeatedly matching it against the pattern, * until all matches have been found and recorded. */ @@ -824,22 +907,30 @@ f_regexplode (svalue_t *sp) matchp = &matches; while ((rc = rx_exec(reg, text, start)) > 0) { - eval_cost++; - total_evalcost++; - match = (struct regexplode_match *)alloca(sizeof *match); + if (add_eval_cost(1)) + { + /* Evaluation cost exceeded: terminate matching early, but + * let the interpreter loop handle the exception. + */ + rc = 0; + break; + } + + match = mempool_alloc(pool, sizeof *match); if (!match) { - free_regexp(reg); - inter_sp = sp; - errorf("Stack overflow in regexplode()"); + errorf("Out of memory (%zu bytes) in regexplode().\n", + sizeof(*match)); /* NOTREACHED */ return sp; } rx_get_match(reg, text, &(match->start), &(match->end)); start = match->end; + /* add match to the match list */ *matchp = match; matchp = &match->next; num_match++; + if (start == mstrsize(text) || (match->start == start && ++start == mstrsize(text)) ) break; @@ -848,8 +939,6 @@ f_regexplode (svalue_t *sp) if (rc < 0) /* Premature abort on error */ { const char * emsg = rx_error_message(rc, reg); - free_regexp(reg); - inter_sp = sp; errorf("regexp: %s\n", emsg); /* NOTREACHED */ return NULL; @@ -864,17 +953,14 @@ f_regexplode (svalue_t *sp) arraysize = 2 * num_match + 1; if (max_array_size && arraysize > (long)max_array_size-1 ) { - free_regexp(reg); - inter_sp = sp; - errorf("Illegal array size"); + errorf("Illegal array size: %"PRIdPINT".\n", arraysize); /* NOTREACHED */ return sp; } ret = allocate_array(arraysize); - /* Walk down the list of matches, extracting the - * text parts and matched delimiters, copying them - * into ret. + /* Walk down the list of matches, extracting the text parts and matched + * delimiters, copying them into ret. */ svp = ret->item; start = 0; @@ -886,11 +972,13 @@ f_regexplode (svalue_t *sp) len = match->start - start; if (len) { - memsafe(txt = mstr_extract(text, start, match->start-1), (size_t)len, "text before delimiter"); + memsafe(txt = mstr_extract(text, start, match->start-1), + (size_t)len, "text before delimiter"); put_string(svp, txt); } else put_ref_string(svp, STR_EMPTY); + svp++; /* Copy the matched delimiter */ @@ -904,6 +992,7 @@ f_regexplode (svalue_t *sp) } else put_ref_string(svp, STR_EMPTY); + svp++; } @@ -925,15 +1014,12 @@ f_regexplode (svalue_t *sp) put_ref_string(svp, STR_EMPTY); } - /* Cleanup */ - free_regexp(reg); - free_svalue(sp); - sp--; - free_svalue(sp); - sp--; - free_svalue(sp); + /* Cleanup: free error handler and 3 arguments. Freeing the error handler + * will free the regexp and the chain of matches. */ + sp = pop_n_elems(4, sp); /* Return the result */ + sp++; put_array(sp, ret); return sp; } /* f_regexplode() */ @@ -1062,8 +1148,7 @@ f_regreplace (svalue_t *sp) rcp->reg = reg; rcp->matches = NULL; - push_error_handler(regreplace_cleanup, &(rcp->head)); - sp = inter_sp; + sp = push_error_handler(regreplace_cleanup, &(rcp->head)); /* Loop over , repeatedly matching it against the pattern, * until all matches have been found and recorded. @@ -1074,8 +1159,15 @@ f_regreplace (svalue_t *sp) reslen = 0; while ((rc = rx_exec(reg, text, start)) > 0) { - eval_cost++; - total_evalcost++; + if (add_eval_cost(1)) + { + /* Evaluation cost exceeded: terminate the matching early, + * but let the interpreter handle the exception. + */ + rc = 0; + break; + } + xallocate(match, sizeof(*match), "regreplace match structure"); rx_get_match(reg, text, &(match->start), &(match->end)); match->sub = NULL; @@ -1289,9 +1381,9 @@ v_regmatch (svalue_t *sp, int num_arg) startpos = (size_t)argp[3].u.number; if (startpos > mstrsize(text)) { - errorf("regmatch(): Start index out of range: %ld, " - "should be in [0..%ld]\n" - , (long)argp[3].u.number, (long)mstrsize(text) + errorf("regmatch(): Start index out of range: %zu, " + "should be in [0..%zu]\n", + startpos, mstrsize(text) ); /* NOTREACHED */ startpos = 0; @@ -1556,7 +1648,7 @@ v_trim (svalue_t *sp, int num_arg) = { '\t', ' ', '\0' }; char *strip; /* String of characters to strip */ size_t strip_l; /* Length of *strip */ - int where; + p_int where; /* Get and test the arguments */ argp = sp - num_arg + 1; @@ -1569,20 +1661,21 @@ v_trim (svalue_t *sp, int num_arg) { where = argp[1].u.number; if (!where) - where = TRIM_LEFT|TRIM_RIGHT; - if (where & ~(TRIM_LEFT|TRIM_RIGHT)) - errorf("Bad argument 2 to trim(): illegal value %ld\n", (long)where); + where = TRIM_BOTH; + if (where > TRIM_BOTH) + errorf("Bad argument 2 to trim(): illegal value %"PRIdPINT"\n", + where); } else - where = TRIM_LEFT|TRIM_RIGHT; + where = TRIM_BOTH; if (num_arg > 2) { if (argp[2].type == T_NUMBER) { if (argp[2].u.number <= 0 || argp[2].u.number >= 1 << CHAR_BIT) - errorf("Bad argument 3 to trim(): %ld is not a character\n" - , argp[2].u.number); + errorf("Bad argument 3 to trim(): %"PRIdPINT + " is not a character\n", argp[2].u.number); def_ch[0] = (char)argp[2].u.number; def_ch[1] = '\0'; strip = def_ch; @@ -2359,10 +2452,10 @@ e_terminal_colour ( string_t * text, mapping_t * map, svalue_t * cl if (pt - tmpmem + ((l < 0) ? -l : l) >= (ptrdiff_t)tmpmem_size) { - errorf("Partial string '%s' too long (%ld+%ld >= %ld).\n" + errorf("Partial string '%s' too long (%td+%"PRIdPINT" >= %zu).\n" , p - , (long)(pt - tmpmem), (long)((l < 0) ? -l : l) - , (long)tmpmem_size); + , (ptrdiff_t)(pt - tmpmem), ((l < 0) ? -l : l) + , tmpmem_size); /* NOTREACHED */ return NULL; } @@ -2573,12 +2666,12 @@ e_terminal_colour ( string_t * text, mapping_t * map, svalue_t * cl && (!indent_overflows || (long)(cp - get_txt(deststr)) != wrap) ) { fatal("Length miscalculated in terminal_colour()\n" - " Expected: %i (or %i) Was: %ld\n" + " Expected: %i (or %i) Was: %td\n" " In string: %.*s\n" " Out string: %.*s\n" " Indent: %i Wrap: %i, indent overflow: %s\n" , j, wrap - , (long)(cp - get_txt(deststr)) + , (ptrdiff_t)(cp - get_txt(deststr)) , (int)mstrsize(text), get_txt(text) , (int)mstrsize(deststr), get_txt(deststr) , indent, wrap @@ -2729,10 +2822,11 @@ process_value (const char *str, Bool original) */ if (original) { - func = alloca(strlen(str)+1); + /* allocate memory and push error handler */ + func = xalloc_with_error_handler(strlen(str)+1); if (!func) - errorf("Out of stack memory (%lu bytes)\n" - , (unsigned long)(strlen(str)+1)); + errorf("Out of memory (%zu bytes) in process_value().\n" + , strlen(str)+1); strcpy(func, str); } else @@ -2749,6 +2843,9 @@ process_value (const char *str, Bool original) */ if ( NULL == (func2 = find_tabled_str(func)) ) { + /* free the error handler if necessary. */ + if (original) + free_svalue(inter_sp--); return NULL; } @@ -2767,6 +2864,9 @@ process_value (const char *str, Bool original) if (!ob) { + /* free the error handler if necessary. */ + if (original) + free_svalue(inter_sp--); return NULL; } @@ -2785,11 +2885,17 @@ process_value (const char *str, Bool original) narg++; } } - - /* Apply the function and see if adequate answer is returned. - */ + + /* Apply the function */ ret = apply(func2, ob, numargs); + /* Free func by freeing the error handler (if we allocated func). + * Has to be done now, after the arguments have been popped by apply(). + */ + if (original) + free_svalue(inter_sp--); + + /* see if adequate answer is returned by the apply(). */ if (ret && ret->type == T_STRING) return ret->u.str; /* The svalue is stored statically in apply_return_value */ @@ -4097,15 +4203,14 @@ v_clones (svalue_t *sp, int num_arg) } #if defined(DYNAMIC_COSTS) - eval_cost += checked / 100 + found / 256; - total_evalcost += checked / 100 + found / 256; + (void)add_eval_cost(checked / 100 + found / 256); #endif /* DYNAMIC_COSTS */ /* Create the result and put it onto the stack */ if (max_array_size && found > max_array_size) { xfree(ores); - errorf("Illegal array size: %ld\n", (long)found); + errorf("Illegal array size: %zu\n", found); /* NOTREACHED */ return sp; } @@ -4113,8 +4218,8 @@ v_clones (svalue_t *sp, int num_arg) if (!res) { xfree(ores); - errorf("(clones) Out of memory: array[%lu] for result.\n" - ,(unsigned long) found); + errorf("(clones) Out of memory: array[%zu] for result.\n", + found); /* NOTREACHED */ return sp; } @@ -4229,7 +4334,7 @@ v_object_info (svalue_t *sp, int num_args) } else {} default: - errorf("Illegal value %ld for object_info().\n", sp->u.number); + errorf("Illegal value %"PRIdPINT" for object_info().\n", sp->u.number); /* NOTREACHED */ return sp; @@ -4431,15 +4536,15 @@ v_object_info (svalue_t *sp, int num_args) #ifdef USE_INVENTORIES svalue_t * -f_present_clone (svalue_t *sp) +v_present_clone (svalue_t *sp, int num_arg) /* EFUN present_clone() * - * object present_clone(string str, object env) - * object present_clone(object obj, object env) + * object present_clone(string str [, object env] [, [int n]) + * object present_clone(object obj [, object env] [, [int n]) * - * Search in the inventory of for the first object with the - * same blueprint as object , resp. for the first object with + * Search in the inventory of for the th object with the + * same blueprint as object , resp. for the th object with * the loadname , and return that object. * * If not found, 0 is returned. @@ -4448,27 +4553,79 @@ f_present_clone (svalue_t *sp) { string_t * name; /* the shared loadname to look for */ object_t *obj; /* the object under scrutiny */ + object_t *env; /* the environment to search in */ + p_int count; /* the object is searched */ - /* Test and get the arguments from the stack */ - if (sp[-1].type == T_STRING) + /* Get the arguments */ + svalue_t *arg = sp - num_arg + 1; // first argument + env = current_object; // default + count = -1; + if (num_arg == 3) { - size_t len; - long i; + // if we got 3 args, the third must be a number. + count = arg[2].u.number; + // but 0 and negative ones make no sense. + if (count <= 0) + { + errorf("Bad argument 3 to present_clone(): got %"PRIdPINT + ", expected a positive number.\n",count); + return sp; /* NOT REACHED */ + } + free_svalue(sp--); + num_arg--; + } + if (num_arg == 2) + { + // the second arg may be an object or a number + if (arg[1].type == T_NUMBER) + { + // But it must not be 0 (which is probably a destructed object) + // and we don't accept two numbers (as second and third arg) + if (arg[1].u.number == 0 || count != -1) + { + vefun_arg_error(2, T_OBJECT, T_NUMBER, sp); + return sp; /* NOTREACHED */ + } + count = arg[1].u.number; + if (count < 0) + { + errorf("Bad argument 2 to present_clone(): got %"PRIdPINT + ", expected a positive number or an object.\n",count); + return sp; /* NOT REACHED */ + } + } + else if (arg[1].type == T_OBJECT) + { + env = arg[1].u.ob; + } + free_svalue(sp--); + num_arg--; + } + /* if no number given and count is still ==-1, the for loop below searches + * implicitly for the first object */ + + + /* Get the name/object to search for */ + if (arg->type == T_STRING) + { + size_t len, i; char * end; char * sane_name; char * name0; /* Intermediate name */ - - name0 = get_txt(sp[-1].u.str); - + char * tmpbuf; /* intermediate buffer for stripping any #xxxx */ + + name0 = get_txt(arg->u.str); + tmpbuf = NULL; + /* Normalize the given string and check if it is * in the shared string table. If not, we know that * there is no blueprint with that name */ - /* First, slash of a trailing '#' */ + /* First, slash off a trailing '#' */ - len = mstrsize((sp-1)->u.str); - i = (long)len; + len = mstrsize(arg->u.str); + i = len; end = name0 + len; while (--i > 0) @@ -4481,17 +4638,24 @@ f_present_clone (svalue_t *sp) /* Not a digit: maybe a '#' */ if ('#' == c && len - i > 1) { - name0 = alloca((size_t)i + 1); - if (!name0) - errorf("Out of stack memory.\n"); - strncpy(name0, get_txt(sp[-1].u.str), (size_t)i); + tmpbuf = xalloc(i + 1); + if (!tmpbuf) + { + errorf("Out of memory (%zu bytes) for temporary " + "buffer in present_clone().\n", i+1); + } + strncpy(tmpbuf, get_txt(arg->u.str), i); name0[i] = '\0'; } break; /* in any case */ } } - + /* if we got a clone name, tmpbuf is filled with the BP name. In any + * case, name0 contains now the name to be used. */ + if (tmpbuf) + name0 = tmpbuf; + /* Now make the name sane */ sane_name = (char *)make_name_sane(name0, !compat_mode); @@ -4499,28 +4663,39 @@ f_present_clone (svalue_t *sp) name = find_tabled_str(sane_name); else name = find_tabled_str(name0); - + + /* tmpbuf (and name0 which might point to the same memory) is unneeded + * from now on. Setting both to NULL, just in case somebody uses + * them later below. */ + if (tmpbuf) { + xfree(tmpbuf); + tmpbuf = name0 = NULL; + } } - else if (sp[-1].type == T_OBJECT) + else if (arg->type == T_OBJECT) { - name = sp[-1].u.ob->load_name; + name = arg->u.ob->load_name; } else - efun_gen_arg_error(1, sp[-1].type, sp); + vefun_exp_arg_error(1, TF_STRING|TF_OBJECT, arg->type, sp); obj = NULL; if (name) { /* We have a name, now look for the object */ - for (obj = sp->u.ob->contains; obj != NULL; obj = obj->next_inv) + for (obj = env->contains; obj != NULL; obj = obj->next_inv) { - if (!(obj->flags & O_DESTRUCTED) && name == obj->load_name) + /* check for <= is deliberate, count is -1 if no number is + * given and then the loop is terminated upon the first object + * matching the name. */ + if (!(obj->flags & O_DESTRUCTED) && name == obj->load_name + && --count <= 0) break; } } - /* Assign the result */ - sp = pop_n_elems(2, sp) + 1; + /* Free first argument and assign the result */ + free_svalue(sp); if (obj != NULL) put_ref_object(sp, obj, "present_clone"); else @@ -4557,8 +4732,8 @@ f_set_is_wizard (svalue_t *sp) switch (sp->u.number) { default: - errorf("Bad arg to set_is_wizard(): got %ld, expected -1..1\n" - , sp->u.number); + errorf("Bad arg to set_is_wizard(): got %"PRIdPINT + ", expected -1..1\n", sp->u.number); /* NOTREACHED */ case 0: *flagp &= ~O_IS_WIZARD; is_wizard_used = MY_TRUE; break; case 1: *flagp |= O_IS_WIZARD; is_wizard_used = MY_TRUE; break; @@ -4762,7 +4937,7 @@ f_abs (svalue_t *sp) { if (sp->u.number == PINT_MIN) { - errorf("Numeric overflow: abs(%ld)\n", (long)sp->u.number); + errorf("Numeric overflow: abs(%"PRIdPINT")\n", sp->u.number); /* NOTREACHED */ return NULL; } @@ -4924,7 +5099,7 @@ f_atan (svalue_t *sp) { d = atan((double)(sp->u.number)); if (d < (-DBL_MAX) || d > DBL_MAX) - errorf("Numeric overflow: atan(%ld)\n", (long)sp->u.number); + errorf("Numeric overflow: atan(%"PRIdPINT")\n", sp->u.number); } else { @@ -5021,7 +5196,7 @@ f_exp (svalue_t *sp) { d = exp((double)sp->u.number); if (d < (-DBL_MAX) || d > DBL_MAX) - errorf("Numeric overflow: exp(%ld)\n", (long)sp->u.number); + errorf("Numeric overflow: exp(%"PRIdPINT")\n", sp->u.number); } else { @@ -5341,7 +5516,7 @@ f_to_string (svalue_t *sp) break; case T_NUMBER: - sprintf(buf,"%ld", sp->u.number); + sprintf(buf,"%"PRIdPINT, sp->u.number); if (buf[sizeof(buf)-1] != '\0') fatal("Buffer overflow in to_string(): " "int number too big.\n"); @@ -5624,7 +5799,8 @@ v_to_struct (svalue_t *sp, int num_arg) , typename(argp[1].type)); if (VEC_SIZE(argp->u.vec) > struct_size(argp[1].u.strct)) { - errorf("Too many elements for struct %s: %ld, expected %ld\n" + errorf("Too many elements for struct %s: %"PRIdPINT + ", expected %ld\n" , get_txt(struct_name(argp[1].u.strct)) , VEC_SIZE(argp->u.vec) , (long)struct_size(argp[1].u.strct) @@ -5661,7 +5837,8 @@ v_to_struct (svalue_t *sp, int num_arg) , typename(argp[1].type)); if (VEC_SIZE(argp->u.vec) > struct_size(argp[1].u.strct)) { - errorf("Too many elements for struct %s: %ld, expected %ld\n" + errorf("Too many elements for struct %s: %"PRIdPINT + ", expected %ld\n" , get_txt(struct_name(argp[1].u.strct)) , VEC_SIZE(argp->u.vec) , (long)struct_size(argp[1].u.strct) @@ -5954,7 +6131,7 @@ f_copy (svalue_t *sp) check_map_for_destr(old); new = copy_mapping(old); if (!new) - errorf("(copy) Out of memory: mapping[%lu] for copy.\n" + errorf("(copy) Out of memory: mapping[%"PRIdPINT"] for copy.\n" , MAP_SIZE(old)); free_mapping(old); sp->u.map = new; @@ -5969,6 +6146,7 @@ f_copy (svalue_t *sp) /*-------------------------------------------------------------------------*/ /* Data packet passed to deep_copy_mapping() during a mapping walk. + * TODO: change width to p_int, because mappings can have p_int values */ struct csv_info { int depth; /* Depth of the copy procedure */ @@ -6058,8 +6236,7 @@ copy_svalue (svalue_t *dest, svalue_t *src size = (mp_int)VEC_SIZE(old); DYN_ARRAY_COST(size); #if defined(DYNAMIC_COSTS) - eval_cost += (depth+1) / 10; - total_evalcost += (depth+1) / 10; + (void)add_eval_cost((depth+1) / 10); #endif /* Create a new array, assign it to dest, and store @@ -6121,8 +6298,7 @@ copy_svalue (svalue_t *dest, svalue_t *src size = (mp_int)struct_size(old); DYN_ARRAY_COST(size); #if defined(DYNAMIC_COSTS) - eval_cost += (depth+1) / 10; - total_evalcost += (depth+1) / 10; + (void)add_eval_cost((depth+1) / 10); #endif /* Create a new array, assign it to dest, and store @@ -6181,14 +6357,13 @@ copy_svalue (svalue_t *dest, svalue_t *src */ DYN_MAPPING_COST(size); #if defined(DYNAMIC_COSTS) - eval_cost += (depth+1) / 10; - total_evalcost += (depth+1) / 10; + (void)add_eval_cost((depth+1) / 10); #endif info.depth = depth+1; info.width = old->num_values; new = allocate_mapping(size, info.width); if (!new) - errorf("(copy) Out of memory: new mapping[%lu, %u].\n" + errorf("(copy) Out of memory: new mapping[%"PRIdMPINT", %u].\n" , size, info.width); put_mapping(dest, new); rec->data = new; @@ -6641,7 +6816,7 @@ v_member (svalue_t *sp, int num_arg) if (hasStart && startpos < 0) { - errorf("Illegal arg 3 to member(): %ld, expected positive number.\n" + errorf("Illegal arg 3 to member(): %"PRIdPINT", expected positive number.\n" , startpos); /* NOTREACHED */ return sp; @@ -6868,7 +7043,7 @@ v_rmember (svalue_t *sp, int num_arg) if (hasStart && startpos < 0) { - errorf("Illegal arg 3 to rmember(): %ld, expected positive number.\n" + errorf("Illegal arg 3 to rmember(): %"PRIdPINT", expected positive number.\n" , startpos); /* NOTREACHED */ return sp; @@ -7985,20 +8160,21 @@ v_debug_info (svalue_t *sp, int num_arg) add_message("O_REPLACED : %s\n", flags&O_REPLACED ?"TRUE":"FALSE"); #ifdef USE_SET_LIGHT - add_message("total light : %d\n", ob->total_light); + add_message("total light : %d\n", (int)ob->total_light); #endif - add_message("time_reset : %ld\n", (long)ob->time_reset); - add_message("time_of_ref : %ld\n", (long)ob->time_of_ref); - add_message("ref : %ld\n", ob->ref); + add_message("time_reset : %"PRIdMPINT"\n", ob->time_reset); + add_message("time_of_ref : %"PRIdMPINT"\n", ob->time_of_ref); + add_message("ref : %"PRIdPINT"\n", ob->ref); #ifdef USE_PARANOIA - add_message("extra_ref : %ld\n", ob->extra_ref); + add_message("extra_ref : %"PRIdPINT"\n", ob->extra_ref); #endif if (ob->gigaticks) - add_message("evalcost : %lu%09lu\n", ob->gigaticks, ob->ticks); + add_message("evalcost : %"PRIuMPINT"%09"PRIuMPINT"\n", + (mp_uint)ob->gigaticks, (mp_uint)ob->ticks); else - add_message("evalcost : %lu\n", ob->ticks); + add_message("evalcost : %"PRIdMPINT"\n", (mp_uint)ob->ticks); #ifdef USE_SWAP - add_message("swap_num : %ld\n", O_SWAP_NUM(ob)); + add_message("swap_num : %"PRIdPINT"\n", O_SWAP_NUM(ob)); #endif add_message("name : '%s'\n", get_txt(ob->name)); add_message("load_name : '%s'\n", get_txt(ob->load_name)); @@ -8034,23 +8210,26 @@ v_debug_info (svalue_t *sp, int num_arg) errorf("Out of memory: unswap object '%s'\n", get_txt(sp->u.ob->name)); #endif pg = sp->u.ob->prog; - add_message("program ref's %3ld\n", pg->ref); + add_message("program ref's %3"PRIdPINT"\n", pg->ref); add_message("Name: '%s'\n", get_txt(pg->name)); - add_message("program size %6ld\n" - ,(long)(PROGRAM_END(*pg) - pg->program)); - add_message("num func's: %3d (%4ld)\n", pg->num_functions - , (long)(pg->num_functions * sizeof(uint32) + - pg->num_function_names * sizeof(short))); - add_message("num vars: %3d (%4ld)\n", pg->num_variables - , (long)(pg->num_variables * sizeof(variable_t))); + add_message("program size %6"PRIuPINT"\n" + ,(p_uint)(PROGRAM_END(*pg) - pg->program)); + add_message("num func's: %3u (%4"PRIuPINT")\n", + (unsigned int)pg->num_functions, + (p_uint)(pg->num_functions * sizeof(uint32) + + pg->num_function_names * sizeof(short))); + add_message("num vars: %3u (%4"PRIuPINT")\n", + (unsigned int)pg->num_variables, + (p_uint)(pg->num_variables * sizeof(variable_t))); v1 = program_string_size(pg, &v0, &v2); - add_message("num strings: %3d (%4ld) : overhead %ld + data %ld (%ld)\n" - , pg->num_strings - , (long)(v0 + v1) - , (long)v0 - , (long)v1 - , (long)v2 + add_message("num strings: %3u (%4"PRIdMPINT") : overhead %"PRIdMPINT + "+ data %"PRIdMPINT" (%"PRIdMPINT")\n" + , (unsigned int)pg->num_strings + , v0 + v1 + , v0 + , v1 + , v2 ); { @@ -8065,14 +8244,15 @@ v_debug_info (svalue_t *sp, int num_arg) ) cnt++; } - add_message("num inherits %3d (%4ld)\n", cnt - , (long)(pg->num_inherited * sizeof(inherit_t))); + add_message("num inherits %3d (%4"PRIuPINT")\n", cnt + , (p_uint)(pg->num_inherited * sizeof(inherit_t))); } - add_message("total size %6ld\n" + add_message("total size %6"PRIdPINT"\n" ,pg->total_size); v1 = data_size(sp->u.ob, &v2); - add_message("data size %6ld (%6ld)\n", v1, v2); + add_message("data size %6"PRIdMPINT" (%6"PRIdMPINT")\n", + v1, v2); break; } @@ -8401,14 +8581,19 @@ v_debug_info (svalue_t *sp, int num_arg) put_string(&res, new_mstring(sbuf.buf)); strbuf_free(&sbuf); } + else if (sp->u.number == DIT_CURRENT_DEPTH) + { + put_number(&res, control_stack_depth()); + } else - errorf("bad arg 2 to debug_info(): %ld, expected 0..2\n" + errorf("bad arg 2 to debug_info(): %"PRIdPINT", expected 0..2\n" , sp->u.number); break; } default: - errorf("Bad debug_info() request value: %ld\n", arg[0].u.number); + errorf("Bad debug_info() request value: %"PRIdPINT"\n", + arg[0].u.number); /* NOTREACHED */ break; } @@ -8438,9 +8623,10 @@ x_gm_localtime (svalue_t *sp, Bool localTime) if (sp->type != T_NUMBER) { if (VEC_SIZE(sp->u.vec) != 2) - errorf("Bad arg 1 to %s(): Invalid array size %ld, expected 2.\n" + errorf("Bad arg 1 to %s(): Invalid array size %"PRIdPINT + ", expected 2.\n" , localTime ? "localtime" : "gmtime" - , (long)VEC_SIZE(sp->u.vec)); + , VEC_SIZE(sp->u.vec)); if (sp->u.vec->item[0].type != T_NUMBER) errorf("Bad arg 1 to %s(): Element 0 is '%s', expected 'int'.\n" , localTime ? "localtime" : "gmtime" @@ -8547,6 +8733,7 @@ f_localtime (svalue_t *sp) /*-------------------------------------------------------------------------*/ svalue_t * f_mktime (svalue_t *sp) +#if 1 /* PSYCLPC VERSION */ /* EFUN mktime * wrapper around libc mktime * argument format is the same as the output of localtime (E) @@ -8629,8 +8816,71 @@ f_mktime (svalue_t *sp) } return sp; -} /* f_mktime */ +#else /* NEW LDMUD VERSION */ +/* EFUN mktime() + * + * int time(int* datum) + * + * Return the unix timestamp (number of seconds ellapsed since 1. Jan 1970, + * 0.0:0 GMT) of the date given in the array datum. datum being an array + * like the one localtime() or gmtime() return: + * int TM_SEC (0) : Seconds (0..59) + * int TM_MIN (1) : Minutes (0..59) + * int TM_HOUR (2) : Hours (0..23) + * int TM_MDAY (3) : Day of the month (1..31) + * int TM_MON (4) : Month of the year (0..11) + * int TM_YEAR (5) : Year (e.g. 2001) + * int TM_WDAY (6) : Day of the week (Sunday = 0) + * int TM_YDAY (7) : Day of the year (0..365) + * int TM_ISDST (8) : TRUE: Daylight saving time + * TM_YDAY and TM_WDAY are ignored (but must also be ints). + * + */ +{ + struct tm * pTm; // broken-down time structure for mktime() + time_t clk; // unix timestamp corresponding to datum + vector_t * v; // just for convenience, stores argument array + int i; + v = sp->u.vec; + if (VEC_SIZE(v) != 9) + errorf("Bad arg 1 to mktime(): Invalid array size %ld, expected 9.\n" + , (long)VEC_SIZE(v)); + // all elements must be ints. + for(i=0; iitem[i].type != T_NUMBER) + errorf("Bad arg 1 to ctime(): Element %d is '%s', expected 'int'.\n" + ,i, efun_arg_typename(v->item[0].type)); + } + + // create the time structure + xallocate(pTm, sizeof(*pTm), "broken-down time structure for mktime()"); + pTm->tm_sec = v->item[TM_SEC].u.number; + pTm->tm_min = v->item[TM_MIN].u.number; + pTm->tm_hour = v->item[TM_HOUR].u.number; + pTm->tm_mday = v->item[TM_MDAY].u.number; + pTm->tm_mon = v->item[TM_MON].u.number; + pTm->tm_year = v->item[TM_YEAR].u.number - 1900; + pTm->tm_isdst = v->item[TM_ISDST].u.number; + + clk = mktime(pTm); + + // free time structure first + xfree(pTm); + + if (clk == -1) + errorf("Specified date/time cannot be represented as unix timestamp.\n"); + + // free argument and put result. + free_svalue(sp); + put_number(sp, (p_int)clk); + + return sp; +#endif +} /* f_mktime() */ + +#if 1 /* PSYCLPC VERSION */ /*-------------------------------------------------------------------------*/ svalue_t * f_strftime (svalue_t *sp) @@ -8657,6 +8907,7 @@ f_strftime (svalue_t *sp) return sp; } /* f_strftime */ +#endif /*-------------------------------------------------------------------------*/ svalue_t * @@ -8684,7 +8935,7 @@ f_strptime (svalue_t *sp) put_number(sp, time_res); return sp; -} /* f_strftime */ +} /* f_strptime */ /*-------------------------------------------------------------------------*/ svalue_t * @@ -8766,7 +9017,7 @@ f_random (svalue_t *sp) if (sp->u.number <= 0) sp->u.number = 0; else - sp->u.number = (p_int)random_number((uint32)sp->u.number); + sp->u.number = (p_int)random_number(sp->u.number); return sp; } /* f_random() */ @@ -8807,49 +9058,92 @@ f_ctime(svalue_t *sp) * * Interpret the argument clock as number of seconds since Jan, * 1st, 1970, 0.00 and convert it to a nice date and time string. + * In this case, the result string will be cached and tabled. * * Alternatively, accept an array of two ints: the first is * value as in the first form, the second int is the number of * microseconds elapsed in the current second. + * In this case the result will not be cached as the value is very + * unlikely to be the same in 2 consecutive calls. */ { char *ts, *cp; string_t *rc; + + static mp_int last_time = -1; // letzte Uhrzeit if (sp->type != T_NUMBER) { + /* utime case */ if (VEC_SIZE(sp->u.vec) != 2) - errorf("Bad arg 1 to ctime(): Invalid array size %ld, expected 2.\n" - , (long)VEC_SIZE(sp->u.vec)); + errorf("Bad arg 1 to ctime(): Invalid array size %"PRIdPINT + ", expected 2.\n", VEC_SIZE(sp->u.vec)); if (sp->u.vec->item[0].type != T_NUMBER) errorf("Bad arg 1 to ctime(): Element 0 is '%s', expected 'int'.\n" , efun_arg_typename(sp->u.vec->item[0].type)); if (sp->u.vec->item[1].type != T_NUMBER) errorf("Bad arg 1 to ctime(): Element 1 is '%s', expected 'int'.\n" , efun_arg_typename(sp->u.vec->item[1].type)); + ts = utime_string( sp->u.vec->item[0].u.number , sp->u.vec->item[1].u.number); + + /* If the string contains nl characters, extract the substring + * before the first one. Else just copy the (volatile) result + * we got. + */ + cp = strchr(ts, '\n'); + if (cp) + { + int len = cp - ts; + memsafe(rc = new_n_mstring(ts, len), len, "ctime() result"); + } + else + { + memsafe(rc = new_mstring(ts), strlen(ts), "ctime() result"); + } } else { - ts = time_string(sp->u.number); - } - - /* If the string contains nl characters, extract the substring - * before the first one. Else just copy the (volatile) result - * we got. - */ - cp = strchr(ts, '\n'); - if (cp) - { - int len = cp - ts; - memsafe(rc = new_n_mstring(ts, len), len, "ctime() result"); - } - else - { - memsafe(rc = new_mstring(ts), strlen(ts), "ctime() result"); - } + /* second-precision case */ + // test if string for this time is cached + if (last_time != sp->u.number) + { + /* cache is outdated */ + ts = time_fstring(sp->u.number, "%a %b %d %H:%M:%S %Y", 0); + + /* If the string contains nl characters, extract the substring + * before the first one. Else just copy the (volatile) result + * we got. + * Table strings, because they are probably used more then once. + */ + cp = strchr(ts, '\n'); + if (cp) + { + int len = cp - ts; + memsafe(rc = new_n_tabled(ts, len), len, + "ctime() result"); + } + else + { + memsafe(rc = new_tabled(ts), strlen(ts), + "ctime() result"); + } + /* fill cache, free last (invalid) string first and don't forget + * to increase the ref count for the cache. */ + free_mstring(last_ctime_result); + last_ctime_result = rc; + ref_mstring(rc); + last_time = sp->u.number; + } + else { + // return last result (and increase ref count) + rc = last_ctime_result; + ref_mstring(rc); + } + } // if (sp->type != T_NUMBER) + free_svalue(sp); put_string(sp, rc); return sp; @@ -8915,5 +9209,111 @@ f_utime (svalue_t *sp) return sp; } /* f_utime() */ + +/*-------------------------------------------------------------------------*/ +#if 0 /* NEW LDMUD VERSION */ +svalue_t * +v_strftime(svalue_t *sp, int num_arg) +/* EFUN strftime() + * + * string strftime() + * string strftime(string fmt) + * string strftime(int clock) + * string strftime(string fmt, int clock) + * string strftime(string fmt, int clock, int localized) + * + * Interpret the argument clock as number of seconds since Jan, + * 1st, 1970, 0.00 and convert it to a nice date and time string. + * The formatstring must be given in fmt and may contain the placeholders + * defined in 'man 3 strftime'. + * If localized == MY_TRUE then the time string will be created with the + * locale set in the environment variable LC_TIME + * Defaults: fmt="%c", clock=current_time, localized=MY_TRUE + * NOTE: the returned string will have at most 511 Characters. + * TODO: Implement proper caching of the result. + */ + +{ + char *ts; + string_t *rc = NULL; // ergebnisstring + + /* Begin of arguments on the stack */ + svalue_t *arg = sp - num_arg + 1; + + // defaults: + Bool localized = MY_TRUE; + mp_int clk = current_time; + char *cfmt = "%c"; + + // evaluate arguments + switch(num_arg) { + case 3: + localized = (Bool)arg[2].u.number; + // fall-through + case 2: + if (arg[1].u.number < 0) + errorf("Bad arg 2 to strftime(): got %"PRIdPINT + ", expected 0 .. %"PRIdPINT"\n", + arg[1].u.number, PINT_MAX); + clk = arg[1].u.number; + // fall-through + case 1: + // empty strings default to "%c" => only set fmt if non-empty + if (arg[0].type == T_STRING && mstrsize(arg[0].u.str)) { + cfmt = get_txt(arg[0].u.str); + } + else if (arg[0].type == T_NUMBER) { + if (num_arg>1) // bei > 1 argument nur strings erlaubt + vefun_exp_arg_error(1, TF_STRING, sp->type, sp); + else if (arg[0].u.number >= 0) + clk = arg[0].u.number; + else + errorf("Bad argument 1 to strftime(): got %"PRIdPINT + ", expected 0 .. %"PRIdPINT"\n", + arg[0].u.number, PINT_MAX); + } + break; + } + + ts = time_fstring(clk,cfmt,localized); + memsafe(rc = new_tabled(ts), strlen(ts)+sizeof(string_t), "strftime() result"); + + sp = pop_n_elems(num_arg, sp); + push_string(sp, rc); + + return sp; +} /* v_strftime() */ +#endif + /***************************************************************************/ +/*-------------------------------------------------------------------------*/ +#ifdef GC_SUPPORT + +void +clear_ref_from_efuns (void) + +/* GC support: Clear the refs for the memory containing the (ctime) cache. + */ + +{ + if (last_ctime_result) + clear_string_ref(last_ctime_result); +} /* clear_ref_from_efuns() */ + +/*-------------------------------------------------------------------------*/ +void +count_ref_from_efuns (void) + +/* GC support: Count the refs for the memory containing the (ctime) cache. + */ + +{ + if (last_ctime_result) + count_ref_from_string(last_ctime_result); +} /* count_ref_from_wiz_list() */ + +#endif /* GC_SUPPORT */ + +/*-------------------------------------------------------------------------*/ + diff --git a/src/efuns.h b/src/efuns.h index 5e7fe1d..4588379 100644 --- a/src/efuns.h +++ b/src/efuns.h @@ -76,21 +76,26 @@ extern svalue_t *f_localtime (svalue_t *sp); extern svalue_t *f_blueprint (svalue_t *sp); extern svalue_t *v_clones (svalue_t *sp, int num_args); extern svalue_t *v_object_info (svalue_t *sp, int num_args); -extern svalue_t *f_present_clone (svalue_t *sp); +extern svalue_t *v_present_clone (svalue_t *sp, int num_arg); extern svalue_t *f_to_object(svalue_t *sp); extern svalue_t *f_set_is_wizard(svalue_t *sp); /* optional */ extern svalue_t *tell_room(svalue_t *sp); extern svalue_t *f_ctime(svalue_t *); +extern svalue_t *v_strftime(svalue_t *, int num_arg); extern svalue_t *v_debug_info(svalue_t *sp, int num_arg); extern svalue_t *f_rusage(svalue_t *sp); extern svalue_t *f_random(svalue_t *); extern svalue_t *f_shutdown(svalue_t *sp); extern svalue_t *f_time(svalue_t *); -extern svalue_t *f_utime(svalue_t *); -extern svalue_t *f_mktime(svalue_t *); extern svalue_t *f_strftime(svalue_t *); extern svalue_t *f_strptime(svalue_t *); +extern svalue_t *f_mktime(svalue_t *); +extern svalue_t *f_utime(svalue_t *); +#ifdef GC_SUPPORT +extern void clear_ref_from_efuns(void); +extern void count_ref_from_efuns(void); +#endif /* GC_SUPPORT */ #endif /* EFUNS_H__ */ diff --git a/src/files.c b/src/files.c index d5f388d..6ef59c8 100644 --- a/src/files.c +++ b/src/files.c @@ -46,7 +46,7 @@ extern int lstat(const char *, struct stat *); #ifdef SunOS4 # if !defined (__GNUC__) || __GNUC__ < 2 || __GNUC__ == 2 && __GNUC_MINOR__ < 7 -extern int lstat(CONST char *, struct stat *); +extern int lstat (CONST char *, struct stat *); # endif extern int fchmod(int, int); #endif @@ -74,10 +74,6 @@ extern int fchmod(int, int); #include "../mudlib/sys/files.h" -/* TODO: The move/copy code is a derivate of the GNU fileutils. Rewrite - * TODO:: it, replace it by the BSD code, or put the driver under the GPL. - */ - /*-------------------------------------------------------------------------*/ static Bool isdir (const char *path) @@ -115,95 +111,81 @@ copy_file (const char *from, const char *to, int mode) */ { - int ifd; - int ofd; - char buf[1024 * 8]; - int len; /* Number of bytes read into `buf'. */ - - if (unlink(to) && errno != ENOENT) + int fromfd, tofd; + ssize_t count; + char buf[4096]; + + fromfd = ixopen(from, O_RDONLY); + if (fromfd < 0) { - debug_message("copy_file(): cannot remove `%s'\n", to); + debug_message("copy_file(): can't open '%s': %s\n", from, strerror(errno)); + return 1; + } + + /* We have to unlink 'to', because it may be a symlink. + O_CREAT won't remove that. */ + if (unlink(to) < 0 && errno != ENOENT) + { + debug_message("copy_file(): can't unlink '%s': %s\n", to, strerror(errno)); + close(fromfd); + return 1; + } + + tofd = ixopen3(to, O_WRONLY|O_CREAT|O_TRUNC, mode); + if (tofd < 0) + { + debug_message("copy_file(): can't open '%s': %s\n", to, strerror(errno)); + close(fromfd); return 1; } - ifd = ixopen3(from, O_RDONLY | O_BINARY, 0); - if (ifd < 0) +#ifdef HAVE_FCHMOD + /* We have given the file mode to ixopen3, this is just to counter umask. + So don't worry if this fchmod fails. */ + fchmod(tofd, mode); +#endif + + do { - debug_message("copy_file(): %s: open failed\n", from); - return errno; - } - - ofd = ixopen3(to, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0600); - if (ofd < 0) - { - debug_message("copy_file(): %s: open failed\n", to); - close(ifd); - return 1; - } - -#ifdef HAVE_FCHMOD - if (fchmod(ofd, mode)) - { - debug_message("copy_file(): %s: fchmod failed\n", to); - close(ifd); - close(ofd); - unlink(to); - return 1; - } -#endif + ssize_t written; + + count = read(fromfd, buf, sizeof(buf)); + if (count < 0) + { + debug_message("copy_file(): can't read from '%s': %s\n", from, strerror(errno)); + close(fromfd); + close(tofd); + unlink(to); + return 1; + } + + written = 0; + while (written < count) + { + ssize_t len; + + len = write(tofd, buf + written, count - written); + if (len <= 0) + { + debug_message("copy_file(): can't write to '%s': %s\n", to, strerror(errno)); + close(fromfd); + close(tofd); + unlink(to); + return 1; + } + + written += len; + } + } while (count > 0); FCOUNT_READ(from); FCOUNT_WRITE(to); - while ((len = read(ifd, buf, sizeof (buf))) > 0) - { - int wrote = 0; - char *bp = buf; - - do - { - wrote = write(ofd, bp, len); - if (wrote < 0) - { - debug_message("copy_file(): %s: write failed\n", to); - close(ifd); - close(ofd); - unlink(to); - return 1; - } - bp += wrote; - len -= wrote; - } while (len > 0); - } - - if (len < 0) - { - debug_message("copy_file(): %s: read failed\n", from); - close(ifd); - close(ofd); - unlink(to); - return 1; - } - - if (close (ifd) < 0) - { - debug_message("copy_file(): %s: close failed\n", from); - close(ofd); - return 1; - } - - if (close (ofd) < 0) - { - debug_message("copy_file(): %s: close failed\n", to); - return 1; - } + close(fromfd); + close(tofd); #ifndef HAVE_FCHMOD - if (chmod (to, mode)) - { - debug_message("copy_file(): %s: chmod failed\n", to); - return 1; - } + chmod(to, mode); #endif return 0; @@ -218,80 +200,55 @@ move_file (const char *from, const char *to) */ { - struct stat to_stats, from_stats; - - if (lstat(from, &from_stats) != 0) + struct stat fromstat, tostat; + + if (lstat(from, &fromstat) < 0) { - debug_message("move_file(): %s: lstat failed\n", from); + debug_message("move_file(): can't lstat '%s': %s\n", from, strerror(errno)); return 1; } - - if (lstat (to, &to_stats) == 0) + + if (!lstat(to, &tostat)) { - if (from_stats.st_dev == to_stats.st_dev - && from_stats.st_ino == to_stats.st_ino) + if (fromstat.st_dev == tostat.st_dev + && fromstat.st_ino == tostat.st_ino) { - debug_message("move_file(): '%s' and '%s' are the same file\n", from, to); + /* Same file. */ + debug_message("move_file(): '%s' and '%s' are the same.\n", from, to); return 1; } - - if (S_ISDIR (to_stats.st_mode)) + + if (S_ISDIR(tostat.st_mode)) { - debug_message("move_file(): %s: cannot overwrite directory\n", to); + debug_message("move_file(): destination '%s' is a directory.\n", to); + return 1; + } + } + + if (rename(from, to)) + { + if (errno == EXDEV) + { + if (!S_ISREG(fromstat.st_mode)) + { + debug_message("move_file(): can't move '%s' across filesystems: Not a regular file.\n", to); + return 1; + } + + if (copy_file(from, to, fromstat.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO))) + return 1; + + unlink(from); + } + else + { + debug_message("move_file(): can't rename '%s' to '%s': %s\n", to, from, strerror(errno)); return 1; } - - } - else if (errno != ENOENT) - { - perror("do_move"); - debug_message("move_file(): %s: unknown error\n", to); - return 1; - } -#ifndef RENAME_HANDLES_DIRECTORIES - /* old SYSV */ - if (isdir(from)) - { - char cmd_buf[3*MAXPATHLEN+1]; - - if (strchr(from, '\'') || strchr(to, '\'')) - return 0; - sprintf(cmd_buf, "/usr/lib/mv_dir '%s' '%s'", from, to); - return system(cmd_buf); - } - else -#endif /* RENAME_HANDLES_DIRECTORIES */ - if (rename (from, to) == 0) - { - FCOUNT_DEL(from); - return 0; } - if (errno != EXDEV) - { - debug_message("move_file(): cannot move '%s' to '%s'\n", from, to); - return 1; - } - - /* rename failed on cross-filesystem link. Copy the file instead. */ - - if (!S_ISREG(from_stats.st_mode)) - { - debug_message("move_file(): cannot move '%s' across filesystems: " - "Not a regular file\n", from); - return 1; - } - - if (copy_file(from, to, from_stats.st_mode & 0777)) - return 1; - - if (unlink(from)) - { - debug_message("move_file(): cannot remove '%s'\n", from); - return 1; - } FCOUNT_DEL(from); - + return 0; } /* move_file() */ @@ -1750,7 +1707,7 @@ f_write_file (svalue_t *sp) break; if (sp->u.number & 1) - if (remove(get_txt(file))) + if (remove(get_txt(file)) && errno != ENOENT) { perror("write_file (remove)"); errorf("Could not remove %s: errno %d.\n", get_txt(file), errno); diff --git a/src/func_spec b/src/func_spec index 1d17a9a..3760125 100644 --- a/src/func_spec +++ b/src/func_spec @@ -657,7 +657,7 @@ object first_inventory(object|string default: F_THIS_OBJECT); object next_inventory(object default: F_THIS_OBJECT); void move_object(object|string, object|string); object present(object|string, void|int|object, void|object); -object present_clone(object|string, object default: F_THIS_OBJECT); /* PRELIMINARY */ +object present_clone(object|string, object|int|void, int|void); #ifdef USE_STRUCTS void say(string|mixed *|object|mapping|struct, void|object|object *); #else diff --git a/src/gcollect.c b/src/gcollect.c index deabb16..4587afc 100644 --- a/src/gcollect.c +++ b/src/gcollect.c @@ -94,6 +94,7 @@ #include "closure.h" #include "comm.h" #include "ed.h" +#include "efuns.h" #include "filestat.h" #include "heartbeat.h" #include "interpret.h" @@ -124,6 +125,8 @@ #include "wiz_list.h" #include "xalloc.h" +#include "i-eval_cost.h" + #include "../mudlib/sys/driver_hook.h" /*-------------------------------------------------------------------------*/ @@ -2094,6 +2097,7 @@ garbage_collection(void) mstring_clear_refs(); clear_ref_from_wiz_list(); clear_ref_from_call_outs(); + clear_ref_from_efuns(); #if defined(USE_PARSE_COMMAND) clear_parse_refs(); #endif @@ -2313,6 +2317,7 @@ garbage_collection(void) count_ref_from_wiz_list(); count_ref_from_call_outs(); + count_ref_from_efuns(); if (master_ob) master_ob->ref++; diff --git a/src/heartbeat.c b/src/heartbeat.c index 20e6ba3..ffce533 100644 --- a/src/heartbeat.c +++ b/src/heartbeat.c @@ -57,6 +57,8 @@ #include "wiz_list.h" #include "xalloc.h" +#include "i-eval_cost.h" + #include "../mudlib/sys/debug_info.h" /*-------------------------------------------------------------------------*/ @@ -165,7 +167,7 @@ call_heart_beat (void) error_recovery_info.rt.last = rt_context; error_recovery_info.rt.type = ERROR_RECOVERY_BACKEND; - rt_context = (rt_context_t *)&error_recovery_info; + rt_context = (rt_context_t *)&error_recovery_info.rt; if (setjmp(error_recovery_info.con.text)) { diff --git a/src/i-eval_cost.h b/src/i-eval_cost.h new file mode 100644 index 0000000..752823f --- /dev/null +++ b/src/i-eval_cost.h @@ -0,0 +1,82 @@ +/*--------------------------------------------------------------------------- + * Eval Cost functions. + * + *--------------------------------------------------------------------------- + */ + +#ifndef I_EVAL_COST__ +#define I_EVAL_COST__ + +#include "driver.h" + +#include "interpret.h" + +/*-------------------------------------------------------------------------*/ +static INLINE Bool +add_eval_cost_n (int32 added_cost, uint repetitions) + +/* Increase the evaluation cost by *. Return TRUE if + * this would exceed max_eval_cost, return FALSE if not. + * + * Passing explicitely guards against situations where + * * itself would overflow. + * + * To safeguard the driver against ridiculous executions, the actual eval_cost + * is capped at max_eval_cost+1. + */ + +{ + if (repetitions == 0) + return MY_FALSE; + + if (max_eval_cost) + { + /* Test the evaluation cost against the limit. + * eval_cost < 0 signify a wrap-around - unlikely, but with these crazy + * wizards everything is possible. + */ + if (eval_cost >= max_eval_cost || eval_cost < 0) + return MY_TRUE; + + if (max_eval_cost - eval_cost < added_cost + || (int32)((max_eval_cost - eval_cost) / repetitions) < added_cost + ) + { + total_evalcost += max_eval_cost - eval_cost + 1; + eval_cost = max_eval_cost+1; + return MY_TRUE; + } + } + + eval_cost += added_cost * repetitions; + total_evalcost += added_cost * repetitions; + + return MY_FALSE; +} /* add_eval_cost_n() */ + +/*-------------------------------------------------------------------------*/ + +/* --- Macros --- */ + +/* Increase the eval cost for a non-repetitive action. + */ +#define add_eval_cost(cost) add_eval_cost_n(cost, 1) + +/* Reset the evaluation cost/time counter. + */ +#define CLEAR_EVAL_COST (assigned_eval_cost = eval_cost = 0) + +/* Check if the current evaluation took too long + */ +#define EVALUATION_TOO_LONG() \ + (max_eval_cost && (eval_cost >= max_eval_cost || eval_cost < 0)) + +/* Return the amount of remaining evaluation costs, or MAX_INT if there + * is no real maximum. + */ +#define GET_REMAINING_EVAL_COST() \ + ( max_eval_cost ? ((eval_cost >= max_eval_cost || eval_cost < 0) ? 0 : (max_eval_cost - eval_cost)) : INT32_MAX) + +/***************************************************************************/ + +#endif /* I_EVAL_COST__ */ diff --git a/src/i-svalue_cmp.h b/src/i-svalue_cmp.h index 21f7543..0bc7cd4 100644 --- a/src/i-svalue_cmp.h +++ b/src/i-svalue_cmp.h @@ -37,7 +37,7 @@ svalue_cmp (svalue_t *left, svalue_t *right) */ { - register int d; + register p_int d; if ( 0 != (d = left->type - right->type) ) return d; diff --git a/src/interpret.c b/src/interpret.c index 4e450e8..92ec6ee 100644 --- a/src/interpret.c +++ b/src/interpret.c @@ -242,6 +242,8 @@ #include "wiz_list.h" #include "xalloc.h" +#include "i-eval_cost.h" + #include "../mudlib/sys/driver_hook.h" #include "../mudlib/sys/debug_info.h" #include "../mudlib/sys/trace.h" @@ -269,6 +271,11 @@ struct catch_context svalue_t * save_sp; /* The saved global values */ + + svalue_t catch_value; + /* Holds the value throw()n from within a catch() while the throw + * is executed. + */ }; /* --- struct cache: one entry of the apply cache @@ -329,11 +336,19 @@ struct cache #endif /* Number of entries in the apply cache. */ - +#if CACHE_SIZE > INT_MAX +#error CACHE_SIZE is > INT_MAX. +#endif + /* sanity check - some function rely that CACHE_SIZE fits into int */ /*-------------------------------------------------------------------------*/ /* Tracing */ +#if TOTAL_TRACE_LENGTH > INT_MAX +#error TOTAL_TRACE_LENGTH is > INT_MAX. +#endif +/* sanity check - some function rely that TOTAL_TRACE_LENGTH fits into int */ + int tracedepth; /* Current depth of traced functions. */ @@ -555,6 +570,10 @@ svalue_t apply_return_value = { T_NUMBER }; */ #define SIZEOF_STACK (EVALUATOR_STACK_SIZE<<1) +#if SIZEOF_STACK > INT_MAX +#error SIZEOF_STACK is > INT_MAX. +#endif +/* sanity check - some function rely that SIZEOF_STACK fits into int */ static svalue_t value_stack_array[SIZEOF_STACK+1]; #define VALUE_STACK (value_stack_array+1) @@ -569,12 +588,9 @@ static svalue_t value_stack_array[SIZEOF_STACK+1]; * is the real bottom of the stack. */ -svalue_t catch_value = { T_INVALID } ; - /* Holds the value throw()n from within a catch() while the throw - * is executed. - */ - - +#if MAX_TRACE > INT_MAX +#error MAX_TRACE is > INT_MAX. +#endif #if MAX_USER_TRACE >= MAX_TRACE #error MAX_USER_TRACE value must be smaller than MAX_TRACE! #endif @@ -611,8 +627,8 @@ static Bool runtime_array_range_check = MY_FALSE; */ #ifdef APPLY_CACHE_STAT -p_int apply_cache_hit = 0; -p_int apply_cache_miss = 0; +p_uint apply_cache_hit = 0; +p_uint apply_cache_miss = 0; /* Number of hits and misses in the apply cache. */ #endif @@ -730,39 +746,45 @@ static void check_extra_ref_in_vector(svalue_t *svp, size_t num); * * This function must be called at least whenever the execution leaves * one object for another one. + * + * assign_eval_cost_inl() is the inlinable version used here, + * assign_eval_cost() is used by other compilation units. */ -#define ASSIGN_EVAL_COST \ - if (current_object->user)\ - {\ - unsigned long carry;\ - current_object->user->cost += eval_cost - assigned_eval_cost;\ - carry = current_object->user->cost / 1000000000;\ - if (carry)\ - {\ - current_object->user->gigacost += carry;\ - current_object->user->cost %= 1000000000;\ - }\ - current_object->user->total_cost += eval_cost - assigned_eval_cost;\ - carry = current_object->user->total_cost / 1000000000;\ - if (carry)\ - {\ - current_object->user->total_gigacost += carry;\ - current_object->user->total_cost %= 1000000000;\ - }\ - }\ - current_object->ticks += eval_cost - assigned_eval_cost;\ - {\ - unsigned long carry = current_object->ticks / 1000000000;\ - if (carry)\ - {\ - current_object->gigaticks += carry;\ - current_object->ticks %= 1000000000;\ - }\ - }\ +static INLINE void +assign_eval_cost_inl(void) +{ + unsigned long carry; + if (current_object->user) + { + current_object->user->cost += eval_cost - assigned_eval_cost; + carry = current_object->user->cost / 1000000000; + if (carry) + { + current_object->user->gigacost += carry; + current_object->user->cost %= 1000000000; + } + current_object->user->total_cost += eval_cost - assigned_eval_cost; + carry = current_object->user->total_cost / 1000000000; + if (carry) + { + current_object->user->total_gigacost += carry; + current_object->user->total_cost %= 1000000000; + } + } + current_object->ticks += eval_cost - assigned_eval_cost; + { + carry = current_object->ticks / 1000000000; + if (carry) + { + current_object->gigaticks += carry; + current_object->ticks %= 1000000000; + } + } assigned_eval_cost = eval_cost; +} -void assign_eval_cost(void) { ASSIGN_EVAL_COST } +void assign_eval_cost(void) { assign_eval_cost_inl(); } /*-------------------------------------------------------------------------*/ void @@ -934,7 +956,10 @@ struct protected_lvalue /* .v.type: T_PROTECTED_LVALUE * .v.u.lvalue: the protected value */ - svalue_t protector; /* protects .v.u.lvalue (or its holder) */ + svalue_t protector; + /* additional reference .v.u.lvalue (or its holder) as means of + * protection + */ }; /* --- struct protected_char_lvalue: protect a char in a string @@ -962,12 +987,12 @@ struct protected_range_lvalue { */ svalue_t protector; /* protects .lvalue */ svalue_t *lvalue; /* the original svalue holding the range */ - int index1, index2; /* first and last index of the range */ + int index1, index2; /* first and last index of the range in .lvalue */ int size; /* original size of .lvalue */ /* On creation, .v.u.{vec,str} == .lvalue->u.{vec,str}. - * If that condition no longer holds, the target has been changed and - * the range information (index, size) is no longer valid. + * If that condition no longer holds, the target in .v has been changed + * and the range information (index, size) is no longer valid. */ }; @@ -1546,7 +1571,7 @@ inl_copy_svalue_no_free (svalue_t *to, svalue_t *from) DYN_MAPPING_COST(MAP_SIZE(old)); new = copy_mapping(old); if (!new) - errorf("Out of memory: mapping[%lu] for copy.\n" + errorf("Out of memory: mapping[%"PRIdPINT"] for copy.\n" , MAP_SIZE(old)); free_mapping(old); to->u.map = new; @@ -1565,8 +1590,8 @@ inl_copy_svalue_no_free (svalue_t *to, svalue_t *from) DYN_ARRAY_COST(size); new = allocate_uninit_array((int)size); if (!new) - errorf("Out of memory: array[%lu] for copy.\n" - , (unsigned long) size); + errorf("Out of memory: array[%zu] for copy.\n" + , size); for (i = 0; i < size; i++) assign_svalue_no_free( &new->item[i] , &old->item[i]); @@ -1812,8 +1837,8 @@ assign_svalue (svalue_t *dest, svalue_t *v) { /* Free the svalue. - * If is a lvalue, the loop will traverse the lvalue chain until - * the actual svalue is found. + * If is a (protected) lvalue, the loop will traverse the lvalue + * chain until the actual svalue is found. * If a T_xxx_LVALUE is found, the assignment will be done here * immediately. */ @@ -2132,8 +2157,8 @@ transfer_pointer_range (svalue_t *source) #ifdef NO_NEGATIVE_RANGES if (index1 > index2) - errorf("Illegal range [%ld..%ld] for assignment.\n" - , index1, index2-1 + errorf("Illegal range [%"PRIdMPINT"..%"PRIdMPINT + "] for assignment.\n", index1, index2-1 ); #endif /* NO_NEGATIVE_RANGES */ @@ -2248,8 +2273,8 @@ transfer_protected_pointer_range ( struct protected_range_lvalue *dest #ifdef NO_NEGATIVE_RANGES if (index1 > index2) - errorf("Illegal range [%ld..%ld] for assignment.\n" - , index1, index2-1 + errorf("Illegal range [%"PRIdMPINT"..%"PRIdMPINT + "] for assignment.\n", index1, index2-1 ); #endif /* NO_NEGATIVE_RANGES */ @@ -2318,7 +2343,9 @@ transfer_protected_pointer_range ( struct protected_range_lvalue *dest } else { - /* Not a pointer: just free it */ + /* Not a pointer, or the protected range has changed in size before: + * just free it + */ free_svalue(source); } @@ -2357,8 +2384,8 @@ assign_string_range (svalue_t *source, Bool do_free) #ifdef NO_NEGATIVE_RANGES if (index1 > index2) - errorf("Illegal range [%ld..%ld] for assignment.\n" - , index1, index2-1 + errorf("Illegal range [%"PRIdMPINT"..%"PRIdMPINT + "] for assignment.\n", index1, index2-1 ); #endif /* NO_NEGATIVE_RANGES */ @@ -2430,8 +2457,8 @@ assign_protected_string_range ( struct protected_range_lvalue *dest #ifdef NO_NEGATIVE_RANGES if (index1 > index2) - errorf("Illegal range [%ld..%ld] for assignment.\n" - , index1, index2-1 + errorf("Illegal range [%"PRIdMPINT"..%"PRIdMPINT + "] for assignment.\n", index1, index2-1 ); #endif /* NO_NEGATIVE_RANGES */ @@ -2606,7 +2633,7 @@ inter_add_array (vector_t *q, vector_t **vpp) if (max_array_size && p_size + q_size > max_array_size) { - errorf("Illegal array size: %ld.\n", (long)(p_size + q_size)); + errorf("Illegal array size: %zu.\n", (p_size + q_size)); } /* The optimized array-adding will transfer elements around, rendering @@ -2699,6 +2726,7 @@ inter_add_array (vector_t *q, vector_t **vpp) return r; } /* inter_add_array() */ + /*=========================================================================*/ /* S T A C K */ @@ -2807,7 +2835,8 @@ _pop_stack (void) { #ifdef DEBUG if (inter_sp < VALUE_STACK) - fatal("VM Stack underflow: %ld too low.\n", (long)(VALUE_STACK - inter_sp)); + fatal("VM Stack underflow: %"PRIdMPINT" too low.\n", + (mp_int)(VALUE_STACK - inter_sp)); #endif free_svalue(inter_sp--); } @@ -2839,6 +2868,8 @@ svalue_t * pop_n_elems (int n, svalue_t *sp) { return _pop_n_elems(n, sp); } /*-------------------------------------------------------------------------*/ +static void stack_overflow (svalue_t *sp, svalue_t *fp, bytecode_p pc) + NORETURN; static void stack_overflow (svalue_t *sp, svalue_t *fp, bytecode_p pc) @@ -2850,8 +2881,8 @@ stack_overflow (svalue_t *sp, svalue_t *fp, bytecode_p pc) { if (sp >= &VALUE_STACK[SIZEOF_STACK]) - fatal("Fatal stack overflow: %ld too high.\n" - , (long)(sp - &VALUE_STACK[SIZEOF_STACK]) + fatal("Fatal stack overflow: %"PRIdMPINT" too high.\n" + , (mp_int)(sp - &VALUE_STACK[SIZEOF_STACK]) ); sp = _pop_n_elems(sp-fp, sp); ERROR("stack overflow\n"); @@ -2871,13 +2902,14 @@ push_referenced_mapping (mapping_t *m) } /*-------------------------------------------------------------------------*/ -void +svalue_t * push_error_handler(void (*errorhandler)(svalue_t *), svalue_t *arg) /* Push the () with the argument as error handler * onto the stack. * This means that a new T_LVALUE is created on the stack, pointing * to . itself is setup to be a T_ERROR_HANDLER value. + * Returns new inter_sp. */ { @@ -2887,6 +2919,7 @@ push_error_handler(void (*errorhandler)(svalue_t *), svalue_t *arg) inter_sp++; inter_sp->type = T_LVALUE; inter_sp->u.lvalue = arg; + return inter_sp; } /* push_error_handler() */ /*-------------------------------------------------------------------------*/ @@ -3021,7 +3054,7 @@ get_vector_item (vector_t * vec, svalue_t * i, svalue_t *sp, bytecode_p pc) */ { - int ind; + p_int ind; svalue_t * item; if (i->type != T_NUMBER) @@ -3042,8 +3075,9 @@ get_vector_item (vector_t * vec, svalue_t * i, svalue_t *sp, bytecode_p pc) } if (ind >= VEC_SIZE(vec)) { - ERRORF(("Index for [] out of bounds: %ld, vector size: %lu\n" - , (long)ind, VEC_SIZE(vec))); + ERRORF(("Index for [] out of bounds: %"PRIdPINT + ", vector size: %"PRIdPINT"\n" + , ind, VEC_SIZE(vec))); /* NOTREACHED */ return NULL; } @@ -3070,7 +3104,7 @@ get_vector_r_item (vector_t * vec, svalue_t * i, svalue_t *sp, bytecode_p pc) */ { - int ind; + p_int ind; svalue_t * item; if (i->type != T_NUMBER) @@ -3085,12 +3119,12 @@ get_vector_r_item (vector_t * vec, svalue_t * i, svalue_t *sp, bytecode_p pc) ERROR("Illegal index for [<]: not a positive number.\n"); return NULL; } - if ( (ind = (mp_int)VEC_SIZE(vec) - ind) < 0 - || ind >= (mp_int)VEC_SIZE(vec) + if ( (ind = VEC_SIZE(vec) - ind) < 0 + || ind >= VEC_SIZE(vec) ) { - ERRORF(("Index out of bounds for [<]: %ld, vector size: %lu.\n" - , (long)(i->u.number), VEC_SIZE(vec))); + ERRORF(("Index out of bounds for [<]: %"PRIdPINT", vector size: %" + PRIdPINT".\n", i->u.number, VEC_SIZE(vec))); return NULL; } @@ -3115,7 +3149,7 @@ get_vector_a_item (vector_t * vec, svalue_t * i, svalue_t *sp, bytecode_p pc) */ { - int ind; + p_int ind; svalue_t * item; if (i->type != T_NUMBER) @@ -3126,11 +3160,12 @@ get_vector_a_item (vector_t * vec, svalue_t * i, svalue_t *sp, bytecode_p pc) return NULL; } if (0 > (ind = i->u.number)) - ind = (mp_int)VEC_SIZE(vec) + ind; - if (ind < 0 || ind >= (mp_int)VEC_SIZE(vec)) + ind = VEC_SIZE(vec) + ind; + if (ind < 0 || ind >= VEC_SIZE(vec)) { - ERRORF(("Index out of bounds for [>]: %ld, vector size: %lu.\n" - , (long)(i->u.number), VEC_SIZE(vec))); + ERRORF(("Index out of bounds for [>]: %"PRIdPINT", vector size: %" + PRIdPINT".\n" + , i->u.number, VEC_SIZE(vec))); return NULL; } @@ -3181,8 +3216,9 @@ get_string_item ( svalue_t * svp, svalue_t * i, Bool make_singular if (ind > (mp_int)mstrsize(svp->u.str) ) { - ERRORF(("Index out for [] of bounds: %ld, string length: %ld.\n" - , (long)ind, (long)mstrsize(svp->u.str))); + ERRORF(("Index out for [] of bounds: %"PRIdMPINT + ", string length: %zu.\n" + , ind, mstrsize(svp->u.str))); return NULL; } @@ -3190,14 +3226,15 @@ get_string_item ( svalue_t * svp, svalue_t * i, Bool make_singular { if (!allow_one_past) { - ERRORF(("Index out of bounds for []: %ld, string length: %ld.\n" - , (long)ind, (long)mstrsize(svp->u.str))); + ERRORF(("Index out of bounds for []: %"PRIdMPINT + ", string length: %zu.\n" + , ind, mstrsize(svp->u.str))); return NULL; } else if (!runtime_no_warn_deprecated) warnf( "Warning: Indexing past string end is deprecated: " - "index %ld, string length: %ld.\n" - , (long)ind, (long)mstrsize(svp->u.str) + "index %"PRIdMPINT", string length: %zu.\n" + , ind, mstrsize(svp->u.str) ); } } @@ -3263,8 +3300,9 @@ get_string_r_item (svalue_t * svp, svalue_t * i, Bool make_singular || ind > (mp_int)mstrsize(svp->u.str) ) { - ERRORF(("Index out of bounds for [<]: %ld, string length: %ld\n" - , (long) i->u.number, (long)mstrsize(svp->u.str))); + ERRORF(("Index out of bounds for [<]: %"PRIdPINT + ", string length: %zu\n" + , i->u.number, mstrsize(svp->u.str))); return NULL; } @@ -3272,14 +3310,15 @@ get_string_r_item (svalue_t * svp, svalue_t * i, Bool make_singular { if (!allow_one_past) { - ERRORF(("Index out for [<] of bounds: %ld, string length: %ld.\n" - , (long)ind, (long)mstrsize(svp->u.str))); + ERRORF(("Index out for [<] of bounds: %"PRIdMPINT + ", string length: %zu.\n" + , ind, mstrsize(svp->u.str))); return NULL; } else if (!runtime_no_warn_deprecated) warnf( "Warning: Indexing past string end is deprecated: " - "index %ld, string length: %ld.\n" - , (long)ind, (long)mstrsize(svp->u.str) + "index %"PRIdMPINT", string length: %zu.\n" + , ind, mstrsize(svp->u.str) ); } } @@ -3340,8 +3379,9 @@ get_string_a_item (svalue_t * svp, svalue_t * i, Bool make_singular } if (ind < 0 || ind > (mp_int)mstrsize(svp->u.str)) { - ERRORF(("Index out of bounds for [>]: %ld, string length: %ld\n" - , (long) i->u.number, (long)mstrsize(svp->u.str))); + ERRORF(("Index out of bounds for [>]: %"PRIdPINT + ", string length: %zu\n" + , i->u.number, mstrsize(svp->u.str))); return NULL; } @@ -3349,14 +3389,15 @@ get_string_a_item (svalue_t * svp, svalue_t * i, Bool make_singular { if (!allow_one_past) { - ERRORF(("Index out for [>] of bounds: %ld, string length: %ld.\n" - , (long)ind, (long)mstrsize(svp->u.str))); + ERRORF(("Index out for [>] of bounds: %"PRIdMPINT + ", string length: %zu.\n" + , ind, mstrsize(svp->u.str))); return NULL; } else if (!runtime_no_warn_deprecated) warnf( "Warning: Indexing past string end is deprecated: " - "index %ld, string length: %ld.\n" - , (long)ind, (long)mstrsize(svp->u.str) + "index %"PRIdMPINT", string length: %zu.\n" + , ind, mstrsize(svp->u.str) ); } } @@ -3412,8 +3453,8 @@ check_struct_op (svalue_t * sp, int off_type, int off_value, bytecode_p pc) if (sp[off_type].u.number >= 0 && sp[off_type].u.number >= current_prog->num_structs) { - ERRORF(("Too big struct index: %ld, max %hu\n" - , (long)sp[off_type].u.number, current_prog->num_structs + ERRORF(("Too big struct index: %"PRIdPINT", max %hu\n" + , sp[off_type].u.number, current_prog->num_structs )); } @@ -3516,7 +3557,7 @@ get_struct_item (struct_t * st, svalue_t * i, svalue_t *sp, bytecode_p pc) */ { - int ind; + p_int ind; svalue_t * item; if (i->type == T_SYMBOL || i->type == T_STRING) @@ -3555,9 +3596,9 @@ get_struct_item (struct_t * st, svalue_t * i, svalue_t *sp, bytecode_p pc) if (ind >= struct_size(st)) { ERRORF(("Illegal struct '%s'->: out of bounds: " - "%ld, struct sized: %lu.\n" + "%"PRIdPINT", struct sized: %lu.\n" , get_txt(struct_name(st)) - , (long)ind + , ind , (unsigned long)struct_size(st) )); /* NOTREACHED */ @@ -4089,8 +4130,8 @@ push_protected_indexed_map_lvalue (svalue_t *sp, bytecode_p pc) /* using uints automagically checks for negative indices */ ) { - ERRORF(("Too big subindex for []: value %ld, width %ld.\n" - , sp->u.number, (long)m->num_values)); + ERRORF(("Too big subindex for []: value %"PRIdPINT", width %" + PRIdPINT".\n", sp->u.number, m->num_values)); return NULL; } @@ -4407,7 +4448,7 @@ aindex_lvalue (svalue_t *sp, bytecode_p pc) } /* aindex_lvalue() */ /*-------------------------------------------------------------------------*/ -static INLINE svalue_t * +static svalue_t * protected_index_lvalue (svalue_t *sp, bytecode_p pc) /* Operator F_PROTECTED_INDEX_LVALUE (string|vector &v=sp[0], int i=sp[-1]) @@ -5140,8 +5181,9 @@ range_lvalue (int code, svalue_t *sp) if (++ind2 < 0 || ind2 > size+1) { inter_sp = sp; - errorf("Upper range index out of bounds: %ld, size: %ld.\n" - , (long)i->u.number, (long)size); + errorf("Upper range index out of bounds: %"PRIdPINT + ", size: %"PRIdMPINT".\n" + , i->u.number, size); return NULL; } @@ -5174,8 +5216,9 @@ range_lvalue (int code, svalue_t *sp) if (ind1 < 0 || ind1 > size) { /* Appending (ind1 == size) is allowed */ inter_sp = sp; - errorf("Lower range index out of bounds: %ld, size: %ld.\n" - , (long)i->u.number, (long)size); + errorf("Lower range index out of bounds: %"PRIdPINT + ", size: %"PRIdMPINT".\n" + , i->u.number, size); return NULL; } @@ -5185,8 +5228,9 @@ range_lvalue (int code, svalue_t *sp) if (ind2 < ind1) { inter_sp = sp; - errorf("Range of negative size given: %ld..%ld .\n" - , (long)i->u.number, (long)(i+1)->u.number); + errorf("Range of negative size given: %"PRIdPINT + "..%"PRIdPINT" .\n" + , i->u.number, (i+1)->u.number); return NULL; } @@ -5195,8 +5239,9 @@ range_lvalue (int code, svalue_t *sp) else if (ind2 > size) { inter_sp = sp; - errorf("Upper range index out of bounds: %ld, size: %ld.\n" - , (long)(i+1)->u.number, (long)size); + errorf("Upper range index out of bounds: %"PRIdPINT + ", size: %"PRIdMPINT".\n" + , (i+1)->u.number, size); return NULL; } @@ -5351,8 +5396,9 @@ protected_range_lvalue (int code, svalue_t *sp) if (++ind2 < 0 || ind2 > size) { inter_sp = sp; - errorf("Upper range index out of bounds: %ld, size: %ld.\n" - , (long)i->u.number, (long)size); + errorf("Upper range index out of bounds: %"PRIdPINT + ", size: %"PRIdMPINT".\n" + , i->u.number, size); return NULL; } @@ -5386,8 +5432,9 @@ protected_range_lvalue (int code, svalue_t *sp) { /* Appending (ind1 == size) is allowed */ inter_sp = sp; - errorf("Lower range index out of bounds: %ld, size: %ld.\n" - , (long)i->u.number, (long)size); + errorf("Lower range index out of bounds: %"PRIdPINT + ", size: %"PRIdMPINT".\n" + , i->u.number, size); return NULL; } @@ -6020,15 +6067,18 @@ efun_arg_typename (long type) * string and return it. The type encoding is the one used in * efun_lpc_types[]. * Result is a pointer to a static buffer. + * TODO: this function should use snprintf() for preventing buffer overflows, + * TODO::especially changing svalue_typename is otherwise risky. */ { static char result[400]; int numtypes, i; - + + /* TODO: better write into result and return the static buffer */ if (type == TF_ANYTYPE) return "mixed"; - + result[0] = '\0'; numtypes = sizeof(svalue_typename)/sizeof(svalue_typename[0]); @@ -6378,6 +6428,55 @@ test_efun_args (int instr, int args, svalue_t *argp) } /* test_efun_args() */ +/*-------------------------------------------------------------------------*/ +/* general errorhandler */ +static void +generic_error_handler( svalue_t * arg) +/* The error handler: free the allocated buffer and the errorhandler structure. + * Note: it is static, but the compiler will have to emit a function and + * symbol for this because the address of the function is taken and it is + * therefore not suitable to be inlined. + */ +{ + errorhandler_t *handler = (errorhandler_t *)arg; + if (handler->buff) + xfree(handler->buff); + xfree(handler); +} /* general_error_handler() */ + +/*-------------------------------------------------------------------------*/ +void * +xalloc_with_error_handler(size_t size) +/* Allocates bytes from the heap. Additionally an error handler is + * pushed onto the value stack so that the requested memory is safely freed, + * either by manually freeing the svalue on the stack or during stack + * unwinding during errorf(). + * inter_sp has to point to the top-of-stack before calling and is updated to + * point to the error handler svalue (new top-of-stack)! + */ +{ + void *buffer; + errorhandler_t *handler; + /* get the memory for the handler first and fail if out-of-memory */ + handler = xalloc(sizeof(*handler)); + if (!handler) + { + return NULL; + } + /* then get the requested memory - upon error de-allocate the handler */ + buffer = xalloc(size); + if (!buffer) + { + xfree(handler); + return NULL; + } + handler->buff = buffer; + /* now push error handler onto the value stack */ + push_error_handler(generic_error_handler, &(handler->head)); + return buffer; +} /* alloc_with_error_handler */ + + /*=========================================================================*/ /*-------------------------------------------------------------------------*/ Bool @@ -6699,7 +6798,8 @@ push_error_context (svalue_t *sp, int catch_flags) p->recovery_info.rt.last = rt_context; p->recovery_info.rt.type = ERROR_RECOVERY_CATCH; p->recovery_info.flags = catch_flags; - rt_context = (rt_context_t *)&p->recovery_info; + p->catch_value.type = T_INVALID; + rt_context = (rt_context_t *)&p->recovery_info.rt; return &p->recovery_info.con; } /* push_error_context() */ @@ -6733,7 +6833,7 @@ pop_error_context (void) /*-------------------------------------------------------------------------*/ svalue_t * -pull_error_context (svalue_t *sp) +pull_error_context (svalue_t *sp, svalue_t *msg) /* Restore the context saved by a catch() after a throw() or runtime error * occured. is the current stackpointer and is used to pop the elements @@ -6742,6 +6842,8 @@ pull_error_context (svalue_t *sp) * The function pops the topmost recovery entry, which must be the catch * recovery entry, restores the important global variables and returns * the saved stack pointer. + * + * If is not NULL the caught error message is put there. */ { @@ -6780,6 +6882,12 @@ pull_error_context (svalue_t *sp) csp = p->save_csp; pop_n_elems(sp - p->save_sp); command_giver = p->save_command_giver; + + /* Save the error message */ + if (msg) + transfer_svalue_no_free(msg, &p->catch_value); + else + free_svalue(&p->catch_value); /* Remove the context from the context stack */ rt_context = p->recovery_info.rt.last; @@ -6788,6 +6896,19 @@ pull_error_context (svalue_t *sp) return sp; } /* pull_error_context() */ +/*-------------------------------------------------------------------------*/ +void +transfer_error_message (svalue_t *v, rt_context_t *rt) + /* Saves the message in the error context assuming that + * it's a catch recovery context. is freed afterwards. + */ +{ + struct catch_context *p; + + p = (struct catch_context *)rt; + transfer_svalue_no_free(&p->catch_value, v); +} + /*-------------------------------------------------------------------------*/ void push_control_stack ( svalue_t *sp @@ -6809,8 +6930,9 @@ push_control_stack ( svalue_t *sp { if (!num_error || csp == &CONTROL_STACK[MAX_TRACE-1]) { - ERRORF(("Too deep recursion: depth %ld, limit %d user/%d max.\n" - , (long)(csp - CONTROL_STACK + 1) + ERRORF(("Too deep recursion: depth %"PRIdMPINT + ", limit %d user/%d max.\n" + , (mp_int)(csp - CONTROL_STACK + 1) , MAX_USER_TRACE, MAX_TRACE)); } } @@ -6832,6 +6954,9 @@ push_control_stack ( svalue_t *sp csp->function_index_offset = function_index_offset; csp->current_variables = current_variables; csp->break_sp = break_sp; +#ifdef EVAL_COST_TRACE + csp->eval_cost = eval_cost; +#endif } /* push_control_stack() */ /*-------------------------------------------------------------------------*/ @@ -7229,13 +7354,14 @@ setup_new_frame2 (fun_hdr_p funstart, svalue_t *sp } /* setup_new_frame2() */ /*-------------------------------------------------------------------------*/ -static funflag_t +static void setup_new_frame (int fx, program_t *inhProg) /* Setup a call for function in the current program. * If is not NULL, it is the program of the inherited function * to call. - * Result are the flags for the function. + * Result are the flags for the function. Global csp->funstart is set + * to the start of the function bytecode. */ { @@ -7300,10 +7426,12 @@ setup_new_frame (int fx, program_t *inhProg) else flags = setup_new_frame1(fx, 0, 0); - inter_sp = setup_new_frame2( - current_prog->program + (flags & FUNSTART_MASK), inter_sp, MY_FALSE - , MY_FALSE - ); + /* Setting csp->funstart is not just convenient, but also + * required for proper error handling in setup_new_frame2() + */ + csp->funstart = current_prog->program + (flags & FUNSTART_MASK); + + inter_sp = setup_new_frame2(csp->funstart, inter_sp, MY_FALSE, MY_FALSE); #ifdef DEBUG if (!current_object->variables && variable_index_offset) fatal("%s Fatal: new frame for object %p '%s' w/o variables, " @@ -7315,7 +7443,6 @@ setup_new_frame (int fx, program_t *inhProg) if (current_variables) current_variables += variable_index_offset; current_strings = current_prog->strings; - return flags; } /* setup_new_frame() */ /*-------------------------------------------------------------------------*/ @@ -7769,9 +7896,7 @@ again: * eval_cost < 0 signify a wrap-around - unlikely, but with these crazy * wizards everything is possible. */ - ++eval_cost; - ++total_evalcost; - if (max_eval_cost && (eval_cost >= max_eval_cost || eval_cost < 0)) + if (add_eval_cost(1)) { rt_context_t * context; @@ -7781,7 +7906,7 @@ again: printf("%s eval_cost too big %ld\n", time_stamp(), (long)eval_cost); - assign_eval_cost(); + assign_eval_cost_inl(); /* If the error isn't caught, reset the eval costs */ for (context = rt_context @@ -7872,8 +7997,9 @@ again: * (defined) functions. Usually used by the compiler to * handle prototypes (in that case it is the first and only * instruction of the generated stub), it is also inserted - * into closures when the object the closure is bound to - * is destructed. + * into lambda closures when they referenced a function + * that went missing because of a replace_program. + * * Note: this instruction MUST be the first in the function. */ @@ -7888,10 +8014,8 @@ again: } else { - /* It is a vanished closure */ - name = STR_CL_OBJ_DESTR; - /* TODO: Which object? This can also happen as result of - * TODO:: a replace_program */ + /* It is a lambda closure after a replace_program. */ + name = STR_DANGLING_LAMBDA; } ERRORF(("Undefined function: %s\n", get_txt(name))); } @@ -7928,7 +8052,7 @@ again: #endif inter_sp = sp; inter_pc = pc; - ASSIGN_EVAL_COST + assign_eval_cost_inl(); sp = (*efun_table[code+EFUN0_OFFSET-TEFUN_OFFSET])(sp); #ifdef CHECK_OBJECT_REF check_all_object_shadows(); @@ -7977,7 +8101,7 @@ again: #endif inter_sp = sp; inter_pc = pc; - ASSIGN_EVAL_COST + assign_eval_cost_inl(); test_efun_args(instruction, 1, sp); sp = (*efun_table[instruction-TEFUN_OFFSET])(sp); #ifdef CHECK_OBJECT_REF @@ -8027,7 +8151,7 @@ again: #endif inter_sp = sp; inter_pc = pc; - ASSIGN_EVAL_COST + assign_eval_cost_inl(); test_efun_args(instruction, 2, sp-1); sp = (*efun_table[instruction-TEFUN_OFFSET])(sp); #ifdef CHECK_OBJECT_REF @@ -8078,7 +8202,7 @@ again: #endif inter_sp = sp; inter_pc = pc; - ASSIGN_EVAL_COST + assign_eval_cost_inl(); test_efun_args(instruction, 3, sp-2); sp = (*efun_table[instruction-TEFUN_OFFSET])(sp); #ifdef CHECK_OBJECT_REF @@ -8128,7 +8252,7 @@ again: #endif inter_sp = sp; inter_pc = pc; - ASSIGN_EVAL_COST + assign_eval_cost_inl(); test_efun_args(instruction, 4, sp-3); sp = (*efun_table[instruction-TEFUN_OFFSET])(sp); #ifdef CHECK_OBJECT_REF @@ -8164,7 +8288,7 @@ again: inter_sp = sp; inter_pc = pc; - ASSIGN_EVAL_COST + assign_eval_cost_inl(); min_arg = instrs[instruction].min_arg; max_arg = instrs[instruction].max_arg; @@ -8560,11 +8684,11 @@ again: */ #ifdef DEBUG if (efp > sp) - fatal("Bad stack at F_RETURN, %ld values too low\n" - , (long)(efp - sp)); + fatal("Bad stack at F_RETURN, %"PRIdMPINT" values too low\n" + , (mp_int)(efp - sp)); else if (efp < sp) - fatal("Bad stack at F_RETURN, %ld values too high\n" - , (long)(sp - efp)); + fatal("Bad stack at F_RETURN, %"PRIdMPINT" values too high\n" + , (mp_int)(sp - efp)); #endif while (sp != fp) { @@ -8594,7 +8718,7 @@ again: { /* eval_instruction() must be left - setup the globals */ - ASSIGN_EVAL_COST + assign_eval_cost_inl(); current_object = csp->ob; previous_ob = csp->prev_ob; inter_pc = csp->pc; @@ -9276,7 +9400,7 @@ again: svalue_t *arg; string_t *str; - assign_eval_cost(); + assign_eval_cost_inl(); num_arg = LOAD_UINT8(pc); /* GET_NUM_ARG doesn't work here either. */ arg = sp - num_arg + 1; @@ -9368,7 +9492,8 @@ again: if (sp->u.number <= 0) { - ERRORF(("Illegal 'reserve' value for catch(): got %ld, expected a positive value.\n" + ERRORF(("Illegal 'reserve' value for catch(): got %"PRIdPINT + ", expected a positive value.\n" , sp->u.number )); } @@ -9442,7 +9567,8 @@ again: { if (svp->u.number == PINT_MAX) { - ERRORF(("Numeric overflow: (%ld)++\n", (long)svp->u.number)); + ERRORF(("Numeric overflow: (%"PRIdPINT")++\n", + svp->u.number)); /* NOTREACHED */ break; } @@ -9504,7 +9630,8 @@ again: { if (svp->u.number == PINT_MIN) { - ERRORF(("Numeric overflow: (%ld)--\n", (long)svp->u.number)); + ERRORF(("Numeric overflow: (%"PRIdPINT")--\n", + svp->u.number)); /* NOTREACHED */ break; } @@ -9567,7 +9694,8 @@ again: { if (svp->u.number == PINT_MAX) { - ERRORF(("Numeric overflow: (%ld)++\n", (long)svp->u.number)); + ERRORF(("Numeric overflow: (%"PRIdPINT")++\n", + svp->u.number)); /* NOTREACHED */ break; } @@ -9629,7 +9757,8 @@ again: { if (svp->u.number == PINT_MIN) { - ERRORF(("Numeric overflow: (%ld)--\n", (long)svp->u.number)); + ERRORF(("Numeric overflow: (%"PRIdPINT")--\n", + svp->u.number)); /* NOTREACHED */ break; } @@ -9690,7 +9819,8 @@ again: { if (svp->u.number == PINT_MAX) { - ERRORF(("Numeric overflow: ++(%ld)\n", (long)svp->u.number)); + ERRORF(("Numeric overflow: ++(%"PRIdPINT")\n", + svp->u.number)); /* NOTREACHED */ break; } @@ -9750,7 +9880,8 @@ again: { if (svp->u.number == PINT_MIN) { - ERRORF(("Numeric overflow: --(%ld)\n", (long)svp->u.number)); + ERRORF(("Numeric overflow: --(%"PRIdPINT")\n", + svp->u.number)); /* NOTREACHED */ break; } @@ -9910,8 +10041,8 @@ again: DYN_STRING_COST(mstrsize(left) + mstrsize(right)) res = mstr_add(left, right); if (!res) - ERRORF(("Out of memory (%lu bytes)\n" - , (unsigned long) mstrsize(left) + mstrsize(right) + ERRORF(("Out of memory (%zu bytes)\n" + , mstrsize(left) + mstrsize(right) )); free_string_svalue(sp); sp--; @@ -9928,16 +10059,14 @@ again: left = (sp-1)->u.str; buff[sizeof(buff)-1] = '\0'; - sprintf(buff, "%ld", sp->u.number); + sprintf(buff, "%"PRIdPINT, sp->u.number); if (buff[sizeof(buff)-1] != '\0') FATAL("Buffer overflow in F_ADD: int number too big.\n"); len = mstrsize(left)+strlen(buff); DYN_STRING_COST(len) res = mstr_add_txt(left, buff, strlen(buff)); if (!res) - ERRORF(("Out of memory (%lu bytes)\n" - , (unsigned long) len - )); + ERRORF(("Out of memory (%zu bytes)\n", len )); pop_n_elems(2); push_string(sp, res); break; @@ -9958,9 +10087,7 @@ again: DYN_STRING_COST(len) res = mstr_add_txt(left, buff, strlen(buff)); if (!res) - ERRORF(("Out of memory (%lu bytes)\n" - , (unsigned long) len - )); + ERRORF(("Out of memory (%zu bytes)\n", len)); sp--; free_string_svalue(sp); put_string(sp, res); @@ -9985,16 +10112,14 @@ again: right = sp->u.str; buff[sizeof(buff)-1] = '\0'; - sprintf(buff, "%ld", (sp-1)->u.number); + sprintf(buff, "%"PRIdPINT, (sp-1)->u.number); if (buff[sizeof(buff)-1] != '\0') FATAL("Buffer overflow in F_ADD: int number too big.\n"); len = mstrsize(right)+strlen(buff); DYN_STRING_COST(len) res = mstr_add_to_txt(buff, strlen(buff), right); if (!res) - ERRORF(("Out of memory (%lu bytes)\n" - , (unsigned long) len - )); + ERRORF(("Out of memory (%zu bytes)\n", len)); free_string_svalue(sp); sp--; /* Overwrite the number at sp */ @@ -10012,8 +10137,8 @@ again: || (left < 0 && right < 0 && PINT_MIN - left > right) ) { - ERRORF(("Numeric overflow: %ld + %ld\n" - , (long)left, (long)right)); + ERRORF(("Numeric overflow: %"PRIdPINT" + %"PRIdPINT"\n" + , left, right)); /* NOTREACHED */ break; } @@ -10030,8 +10155,8 @@ again: sum = (double)((sp-1)->u.number) + READ_DOUBLE(sp); if (sum < (-DBL_MAX) || sum > DBL_MAX) - ERRORF(("Numeric overflow: %ld + %g\n" - , (long)(sp-1)->u.number, READ_DOUBLE(sp))); + ERRORF(("Numeric overflow: %"PRIdPINT" + %g\n" + , (sp-1)->u.number, READ_DOUBLE(sp))); STORE_DOUBLE(sp-1, sum); sp--; sp->type = T_FLOAT; @@ -10064,8 +10189,8 @@ again: { sum = READ_DOUBLE(sp-1) + (double)(sp->u.number); if (sum < (-DBL_MAX) || sum > DBL_MAX) - ERRORF(("Numeric overflow: %g + %ld\n" - , READ_DOUBLE(sp-1), (long)sp->u.number)); + ERRORF(("Numeric overflow: %g + %"PRIdPINT"\n" + , READ_DOUBLE(sp-1), sp->u.number)); STORE_DOUBLE(sp-1, sum); sp--; break; @@ -10085,9 +10210,7 @@ again: DYN_STRING_COST(len) res = mstr_add_to_txt(buff, strlen(buff), right); if (!res) - ERRORF(("Out of memory (%lu bytes)\n" - , (unsigned long) len - )); + ERRORF(("Out of memory (%zu bytes)\n", len)); free_string_svalue(sp); sp--; /* Overwrite the number at sp */ @@ -10132,10 +10255,13 @@ again: { check_map_for_destr(m); if (max_mapping_size && MAP_TOTAL_SIZE(m) > (p_int)max_mapping_size) - ERRORF(("Illegal mapping size: %ld elements (%ld x %ld)\n" + ERRORF(("Illegal mapping size: %"PRIdPINT + " elements (%"PRIdPINT" x %"PRIdPINT")\n" , MAP_TOTAL_SIZE(m), MAP_SIZE(m), m->num_values)); + if (max_mapping_keys && MAP_SIZE(m) > (p_int)max_mapping_keys) - ERRORF(("Illegal mapping size: %ld entries\n", MAP_SIZE(m))); + ERRORF(("Illegal mapping size: %"PRIdPINT" entries\n", + MAP_SIZE(m))); } break; } @@ -10175,8 +10301,8 @@ again: || (left < 0 && right >= 0 && PINT_MIN + right > left) ) { - ERRORF(("Numeric overflow: %ld - %ld\n" - , (long)left, (long)right)); + ERRORF(("Numeric overflow: %"PRIdPINT" - %"PRIdPINT"\n" + , left, right)); /* NOTREACHED */ break; } @@ -10193,8 +10319,8 @@ again: diff = (double)((sp-1)->u.number) - READ_DOUBLE(sp); if (diff < (-DBL_MAX) || diff > DBL_MAX) - ERRORF(("Numeric overflow: %ld - %g\n" - , (long)(sp-1)->u.number, READ_DOUBLE(sp))); + ERRORF(("Numeric overflow: %"PRIdPINT" - %g\n" + , (sp-1)->u.number, READ_DOUBLE(sp))); sp--; STORE_DOUBLE(sp, diff); sp->type = T_FLOAT; @@ -10222,8 +10348,8 @@ again: { diff = READ_DOUBLE(sp-1) - (double)(sp->u.number); if (diff < (-DBL_MAX) || diff > DBL_MAX) - ERRORF(("Numeric overflow: %g - %ld\n" - , READ_DOUBLE(sp-1), (long)sp->u.number)); + ERRORF(("Numeric overflow: %g - %"PRIdPINT"\n" + , READ_DOUBLE(sp-1), sp->u.number)); sp--; STORE_DOUBLE(sp, diff); break; @@ -10311,8 +10437,8 @@ again: || (right != 0 && PINT_MAX / right < left) ) { - ERRORF(("Numeric overflow: %ld * %ld\n" - , (long)left, (long)right)); + ERRORF(("Numeric overflow: %"PRIdPINT" * %"PRIdPINT"\n" + , left, right)); /* NOTREACHED */ break; } @@ -10323,8 +10449,9 @@ again: || (right != 0 && PINT_MAX / right > left) ) { - ERRORF(("Numeric overflow: %ld * %ld\n" - , (long)left, (long)right)); + ERRORF(("Numeric overflow: %"PRIdPINT + " * %"PRIdPINT"\n" + , left, right)); /* NOTREACHED */ break; } @@ -10335,8 +10462,9 @@ again: || (right > 0 && PINT_MIN / right > left) ) { - ERRORF(("Numeric overflow: %ld * %ld\n" - , (long)left, (long)right)); + ERRORF(("Numeric overflow: %"PRIdPINT + " * %"PRIdPINT"\n" + , left, right)); /* NOTREACHED */ break; } @@ -10353,8 +10481,8 @@ again: product = (sp-1)->u.number * READ_DOUBLE(sp); if (product < (-DBL_MAX) || product > DBL_MAX) - ERRORF(("Numeric overflow: %ld * %g\n" - , (long)(sp-1)->u.number, READ_DOUBLE(sp))); + ERRORF(("Numeric overflow: %"PRIdPINT" * %g\n" + , (sp-1)->u.number, READ_DOUBLE(sp))); sp--; STORE_DOUBLE(sp, product); sp->type = T_FLOAT; @@ -10375,14 +10503,14 @@ again: || ( sp[-1].u.number != 0 && PINT_MAX / sp[-1].u.number < (p_int)slen) ) - ERRORF(("Result string too long (%lu * %ld).\n" - , (unsigned long)slen, (long)sp[-1].u.number + ERRORF(("Result string too long (%zu * %"PRIdPINT").\n" + , slen, sp[-1].u.number )); result = mstr_repeat(sp->u.str, (size_t)sp[-1].u.number); if (!result) - ERRORF(("Out of memory (%ld bytes).\n" - , (long)(mstrsize(sp->u.str) * sp[-1].u.number))); + ERRORF(("Out of memory (%"PRIdPINT" bytes).\n" + , (p_int)mstrsize(sp->u.str) * sp[-1].u.number)); DYN_STRING_COST(mstrsize(result)) free_svalue(sp); @@ -10459,8 +10587,8 @@ again: { product = READ_DOUBLE(sp-1) * sp->u.number; if (product < (-DBL_MAX) || product > DBL_MAX) - ERRORF(("Numeric overflow: %g * %ld\n" - , READ_DOUBLE(sp-1), (long)sp->u.number)); + ERRORF(("Numeric overflow: %g * %"PRIdPINT"\n" + , READ_DOUBLE(sp-1), sp->u.number)); STORE_DOUBLE(sp-1, product); sp--; break; @@ -10485,14 +10613,13 @@ again: || ( sp->u.number != 0 && PINT_MAX / sp->u.number < (p_int)slen) ) - ERRORF(("Result string too long (%ld * %lu).\n" - , (long)sp->u.number, (unsigned long)slen - )); + ERRORF(("Result string too long (%"PRIdPINT" * %zu).\n" + , sp->u.number, slen)); result = mstr_repeat(sp[-1].u.str, (size_t)sp->u.number); if (!result) - ERRORF(("Out of memory (%ld bytes).\n" - , (long)(mstrsize(sp[-1].u.str) * sp->u.number))); + ERRORF(("Out of memory (%"PRIdMPINT" bytes).\n" + , (mp_int)mstrsize(sp[-1].u.str) * sp->u.number)); DYN_STRING_COST(mstrsize(result)) @@ -10584,8 +10711,8 @@ again: if (sp->u.number == 0) ERROR("Division by zero\n"); if ((sp-1)->u.number == PINT_MIN && sp->u.number == -1) - ERRORF(("Numeric overflow: %ld / -1\n" - , (long)(sp-1)->u.number + ERRORF(("Numeric overflow: %"PRIdPINT" / -1\n" + , (sp-1)->u.number )); i = (sp-1)->u.number / sp->u.number; sp--; @@ -10603,8 +10730,8 @@ again: sp--; dtmp = (double)sp->u.number / dtmp; if (dtmp < (-DBL_MAX) || dtmp > DBL_MAX) - ERRORF(("Numeric overflow: %ld / %g\n" - , (long)(sp)->u.number, READ_DOUBLE(sp+1))); + ERRORF(("Numeric overflow: %"PRIdPINT" / %g\n" + , (sp)->u.number, READ_DOUBLE(sp+1))); STORE_DOUBLE(sp, dtmp); sp->type = T_FLOAT; break; @@ -10642,8 +10769,8 @@ again: sp--; dtmp = READ_DOUBLE(sp) / dtmp; if (dtmp < (-DBL_MAX) || dtmp > DBL_MAX) - ERRORF(("Numeric overflow: %g / %ld\n" - , READ_DOUBLE(sp), (long)(sp+1)->u.number)); + ERRORF(("Numeric overflow: %g / %"PRIdPINT"\n" + , READ_DOUBLE(sp), (sp+1)->u.number)); STORE_DOUBLE(sp, dtmp); break; } @@ -11368,9 +11495,9 @@ again: /* Slice a range from an array */ vector_t *v; - int size, i1, i2; + p_int size, i1, i2; - size = (int)VEC_SIZE(sp[-2].u.vec); + size = VEC_SIZE(sp[-2].u.vec); if (instruction == F_RANGE || instruction == F_NR_RANGE @@ -11413,21 +11540,25 @@ again: if (i1 < 0 || i1 >= size) { if (i2 < 0 || i2 >= size) - WARNF(("Warning: Out-of-bounds range limits: [%ld..%ld], size %ld.\n" - , (long)i1, (long)i2, (long)size)); + WARNF(("Warning: Out-of-bounds range limits: [%" + PRIdPINT"..%"PRIdPINT"], size %"PRIdPINT".\n" + , i1, i2, size)); else - WARNF(("Warning: Out-of-bounds lower range limits: %ld, size %ld.\n" - , (long)i1, (long)size)); + WARNF(("Warning: Out-of-bounds lower range limits: %" + PRIdPINT", size %"PRIdPINT".\n" + , i1, size)); } else if (i2 < 0 || i2 >= size) { - WARNF(("Warning: Out-of-bounds upper range limits: %ld, size %ld.\n" - , (long)i2, (long)size)); + WARNF(("Warning: Out-of-bounds upper range limits: %" + PRIdPINT", size %"PRIdPINT".\n" + , i2, size)); } else if (i1 > i2) { - WARNF(("Warning: Ranges of negative size: %ld..%ld .\n" - , (long)i1, (long)i2)); + WARNF(("Warning: Ranges of negative size: %"PRIdPINT + "..%"PRIdPINT".\n" + , i1, i2)); } } @@ -11455,10 +11586,10 @@ again: { /* Slice a range from string */ - long len, from, to; + p_int len, from, to; string_t *res; - len = (long)mstrsize(sp[-2].u.str); + len = mstrsize(sp[-2].u.str); if (instruction == F_RANGE || instruction == F_NR_RANGE || instruction == F_NX_RANGE @@ -11519,7 +11650,7 @@ again: if (res == NULL) { - ERRORF(("Out of memory (%ld bytes).\n", to-from+1)); + ERRORF(("Out of memory (%"PRIdPINT" bytes).\n", to-from+1)); } pop_n_elems(3); push_string(sp, res); @@ -11591,9 +11722,7 @@ again: DYN_STRING_COST(len) new_string = mstr_add(left, right); if (!new_string) - ERRORF(("Out of memory (%lu bytes)\n" - , (unsigned long) len - )); + ERRORF(("Out of memory (%zu bytes)\n", len)); free_string_svalue(sp-1); sp -= 2; } @@ -11628,7 +11757,7 @@ again: DYN_STRING_COST(len) new_string = mstr_add_txt(argp->u.str, buff, strlen(buff)); if (!new_string) - ERRORF(("Out of memory (%lu bytes).\n", (unsigned long)len)); + ERRORF(("Out of memory (%zu bytes).\n", len)); sp -= 2; } else @@ -11653,8 +11782,8 @@ again: || (left < 0 && right < 0 && PINT_MIN - left > right) ) { - ERRORF(("Numeric overflow: %ld += %ld\n" - , (long)left, (long)right)); + ERRORF(("Numeric overflow: %"PRIdPINT" += %"PRIdPINT"\n" + , left, right)); /* NOTREACHED */ break; } @@ -11675,8 +11804,8 @@ again: sum = (double)(argp->u.number) + READ_DOUBLE(sp-1); if (sum < (-DBL_MAX) || sum > DBL_MAX) - ERRORF(("Numeric overflow: %ld + %g\n" - , (long)argp->u.number, READ_DOUBLE(sp-1))); + ERRORF(("Numeric overflow: %"PRIdPINT" + %g\n" + , argp->u.number, READ_DOUBLE(sp-1))); argp->type = T_FLOAT; STORE_DOUBLE(argp, sum); if (instruction == F_VOID_ADD_EQ) @@ -11698,16 +11827,14 @@ again: right = (sp-1)->u.str; buff[sizeof(buff)-1] = '\0'; - sprintf(buff, "%ld", argp->u.number); + sprintf(buff, "%"PRIdPINT, argp->u.number); if (buff[sizeof(buff)-1] != '\0') FATAL("Buffer overflow in F_ADD_EQ: int number too big.\n"); len = mstrsize(right)+strlen(buff); DYN_STRING_COST(len) res = mstr_add_to_txt(buff, strlen(buff), right); if (!res) - ERRORF(("Out of memory (%lu bytes)\n" - , (unsigned long) len - )); + ERRORF(("Out of memory (%zu bytes)\n", len)); free_string_svalue(sp-1); /* Overwrite the number in argp */ @@ -11741,8 +11868,8 @@ again: || (left < 0 && right < 0 && PINT_MIN - left > right) ) { - ERRORF(("Numeric overflow: %ld += %ld\n" - , (long)left, (long)right)); + ERRORF(("Numeric overflow: %"PRIdPINT" += %"PRIdPINT"\n" + , left, right)); /* NOTREACHED */ break; } @@ -11781,13 +11908,13 @@ again: { check_map_for_destr(argp->u.map); if (max_mapping_size && MAP_TOTAL_SIZE(argp->u.map) > (p_int)max_mapping_size) - ERRORF(("Illegal mapping size: %ld elements " - "(%ld x %ld)\n" - , MAP_TOTAL_SIZE(argp->u.map) + ERRORF(("Illegal mapping size: %"PRIdMPINT" elements " + "(%"PRIdPINT" x %"PRIdPINT")\n" + , (mp_int)MAP_TOTAL_SIZE(argp->u.map) , MAP_SIZE(argp->u.map) , argp->u.map->num_values)); if (max_mapping_keys && MAP_SIZE(argp->u.map) > (p_int)max_mapping_keys) - ERRORF(("Illegal mapping size: %ld entries\n" + ERRORF(("Illegal mapping size: %"PRIdPINT" entries\n" , MAP_SIZE(argp->u.map) )); } @@ -11842,8 +11969,8 @@ again: d = READ_DOUBLE(argp) + (double)sp[-1].u.number; if (d < (-DBL_MAX) || d > DBL_MAX) - ERRORF(("Numeric overflow: %g + %ld\n" - , READ_DOUBLE(argp), (long)(sp-1)->u.number)); + ERRORF(("Numeric overflow: %g + %"PRIdPINT"\n" + , READ_DOUBLE(argp), (sp-1)->u.number)); STORE_DOUBLE(argp, d); sp -= 2; } @@ -11914,8 +12041,8 @@ again: || (left < 0 && right >= 0 && PINT_MIN + right > left) ) { - ERRORF(("Numeric overflow: %ld -= %ld\n" - , (long)left, (long)right)); + ERRORF(("Numeric overflow: %"PRIdPINT" -= %"PRIdPINT"\n" + , left, right)); /* NOTREACHED */ break; } @@ -11932,8 +12059,8 @@ again: sp--; diff = (double)(argp->u.number) - READ_DOUBLE(sp); if (diff < (-DBL_MAX) || diff > DBL_MAX) - ERRORF(("Numeric overflow: %ld - %g\n" - , (long)argp->u.number, READ_DOUBLE(sp))); + ERRORF(("Numeric overflow: %"PRIdPINT" - %g\n" + , argp->u.number, READ_DOUBLE(sp))); STORE_DOUBLE(sp, diff); sp->type = T_FLOAT; assign_svalue_no_free(argp, sp); @@ -11960,8 +12087,8 @@ again: || (left < 0 && right >= 0 && PINT_MIN + right > left) ) { - ERRORF(("Numeric overflow: %ld -= %ld\n" - , (long)left, (long)right)); + ERRORF(("Numeric overflow: %"PRIdPINT" -= %"PRIdPINT"\n" + , left, right)); /* NOTREACHED */ break; } @@ -12045,8 +12172,8 @@ again: sp--; d = READ_DOUBLE(argp) - (double)sp->u.number; if (d < (-DBL_MAX) || d > DBL_MAX) - ERRORF(("Numeric overflow: %g + %ld\n" - , READ_DOUBLE(argp), (long)sp->u.number)); + ERRORF(("Numeric overflow: %g + %"PRIdPINT"\n" + , READ_DOUBLE(argp), sp->u.number)); STORE_DOUBLE(argp, d); *sp = *argp; } @@ -12142,8 +12269,9 @@ again: || (right != 0 && PINT_MAX / right < left) ) { - ERRORF(("Numeric overflow: %ld *= %ld\n" - , (long)left, (long)right)); + ERRORF(("Numeric overflow: %"PRIdPINT" *= %" + PRIdPINT"\n" + , left, right)); /* NOTREACHED */ break; } @@ -12154,8 +12282,9 @@ again: || (right != 0 && PINT_MAX / right > left) ) { - ERRORF(("Numeric overflow: %ld *= %ld\n" - , (long)left, (long)right)); + ERRORF(("Numeric overflow: %"PRIdPINT" *= %" + PRIdPINT"\n" + , left, right)); /* NOTREACHED */ break; } @@ -12166,8 +12295,9 @@ again: || (right > 0 && PINT_MIN / right > left) ) { - ERRORF(("Numeric overflow: %ld *= %ld\n" - , (long)left, (long)right)); + ERRORF(("Numeric overflow: %"PRIdPINT" *= %" + PRIdPINT"\n" + , left, right)); /* NOTREACHED */ break; } @@ -12183,8 +12313,8 @@ again: product = argp->u.number * READ_DOUBLE(sp); if (product < (-DBL_MAX) || product > DBL_MAX) - ERRORF(("Numeric overflow: %ld * %g\n" - , (long)argp->u.number, READ_DOUBLE(sp))); + ERRORF(("Numeric overflow: %"PRIdPINT" * %g\n" + , argp->u.number, READ_DOUBLE(sp))); STORE_DOUBLE(sp, product); sp->type = T_FLOAT; assign_svalue_no_free(argp, sp); @@ -12214,8 +12344,8 @@ again: || (right != 0 && PINT_MAX / right < left) ) { - ERRORF(("Numeric overflow: %ld *= %ld\n" - , (long)left, (long)right)); + ERRORF(("Numeric overflow: %"PRIdPINT" *= %" + PRIdPINT"\n", left, right)); /* NOTREACHED */ break; } @@ -12226,8 +12356,8 @@ again: || (right != 0 && PINT_MAX / right > left) ) { - ERRORF(("Numeric overflow: %ld *= %ld\n" - , (long)left, (long)right)); + ERRORF(("Numeric overflow: %"PRIdPINT" *= %" + PRIdPINT"\n", left, right)); /* NOTREACHED */ break; } @@ -12238,8 +12368,8 @@ again: || (right > 0 && PINT_MIN / right > left) ) { - ERRORF(("Numeric overflow: %ld *= %ld\n" - , (long)left, (long)right)); + ERRORF(("Numeric overflow: %"PRIdPINT" *= %" + PRIdPINT"\n", left, right)); /* NOTREACHED */ break; } @@ -12268,8 +12398,8 @@ again: { d = READ_DOUBLE(argp) * (double)sp->u.number; if (d < (-DBL_MAX) || d > DBL_MAX) - ERRORF(("Numeric overflow: %g * %ld\n" - , READ_DOUBLE(argp), (long)sp->u.number)); + ERRORF(("Numeric overflow: %g * %"PRIdPINT"\n" + , READ_DOUBLE(argp), sp->u.number)); STORE_DOUBLE(argp, d); *sp = *argp; } @@ -12307,14 +12437,14 @@ again: || ( sp->u.number != 0 && PINT_MAX / sp->u.number < (p_int)len) ) - ERRORF(("Result string too long (%ld * %lu).\n" - , (long)sp->u.number, (unsigned long)len + ERRORF(("Result string too long (%"PRIdPINT" * %zu).\n" + , sp->u.number, len )); reslen = (size_t)sp->u.number * len; result = mstr_repeat(argp->u.str, (size_t)sp->u.number); if (!result) - ERRORF(("Out of memory (%lu bytes).\n", (unsigned long)reslen)); + ERRORF(("Out of memory (%zu bytes).\n", reslen)); DYN_STRING_COST(reslen) @@ -12328,7 +12458,7 @@ again: { vector_t *result; mp_int reslen; - size_t len; + p_uint len; sp--; if (sp->type != T_NUMBER) @@ -12351,7 +12481,7 @@ again: if (sp->u.number > 0 && len) { - size_t left; + p_uint left; svalue_t *from, *to; /* Seed result[] with one copy of the array. @@ -12419,8 +12549,8 @@ again: if (sp->u.number == 0) ERROR("Division by zero\n"); if (argp->u.number == PINT_MIN && sp->u.number == -1) - ERRORF(("Numeric overflow: %ld / -1\n" - , (long)argp->u.number + ERRORF(("Numeric overflow: %"PRIdPINT" / -1\n" + , argp->u.number )); sp->u.number = argp->u.number /= sp->u.number; break; @@ -12436,8 +12566,8 @@ again: ERROR("Division by zero\n"); dtmp = (double)argp->u.number / dtmp; if (dtmp < (-DBL_MAX) || dtmp > DBL_MAX) - ERRORF(("Numeric overflow: %ld / %g\n" - , (long)argp->u.number, READ_DOUBLE(sp))); + ERRORF(("Numeric overflow: %"PRIdPINT" / %g\n" + , argp->u.number, READ_DOUBLE(sp))); STORE_DOUBLE(sp, dtmp); sp->type = T_FLOAT; assign_svalue_no_free(argp, sp); @@ -12489,8 +12619,8 @@ again: ERROR("Division by zero\n"); d = READ_DOUBLE(argp) / (double)i; if (d < (-DBL_MAX) || d > DBL_MAX) - ERRORF(("Numeric overflow: %g / %ld\n" - , READ_DOUBLE(argp), (long)sp->u.number)); + ERRORF(("Numeric overflow: %g / %"PRIdPINT"\n" + , READ_DOUBLE(argp), sp->u.number)); STORE_DOUBLE(argp, d); *sp = *argp; } @@ -13149,17 +13279,17 @@ again: vector_t *vec; /* the array */ svalue_t *svp; /* pointer into the array */ - long i; /* (remaining) vector size */ + p_int i; /* (remaining) vector size */ vec = sp->u.vec; - i = (long)VEC_SIZE(vec); + i = VEC_SIZE(vec); /* Check if there is enough space on the stack. */ if (i + (sp - VALUE_STACK) >= EVALUATOR_STACK_SIZE) { - errorf("VM Stack overflow: %ld too high.\n" - , (long)(i + (sp - VALUE_STACK) - EVALUATOR_STACK_SIZE) ); + errorf("VM Stack overflow: %"PRIdMPINT" too high.\n" + , ((mp_int)i + (sp - VALUE_STACK) - EVALUATOR_STACK_SIZE) ); /* NOTREACHED */ break; } @@ -14561,7 +14691,7 @@ again: int def_narg; /* expected number of arguments */ simul_efun_table_t *entry; - ASSIGN_EVAL_COST /* we're changing objects */ + assign_eval_cost_inl(); /* we're changing objects */ /* Get the sefun code and the number of arguments on the stack */ LOAD_SHORT(code, pc); @@ -14659,9 +14789,9 @@ again: #ifdef DEBUG if (!ob->variables && entry->variable_index_offset) fatal("%s Fatal: call sefun for object %p '%s' w/o variables, " - "but offset %ld\n" + "but offset %"PRIdPINT"\n" , time_stamp(), ob, get_txt(ob->name) - , (long)(entry->variable_index_offset)); + , (entry->variable_index_offset)); #endif current_variables = ob->variables; if (current_variables) @@ -14772,11 +14902,11 @@ again: num_values = num[1]; } - if (max_mapping_size && i * (1+num_values) > (p_int)max_mapping_size) - ERRORF(("Illegal mapping size: %ld elements (%ld x %ld)\n" - , (long)(i * (1+num_values)), (long)i, (long)num_values)); - if (max_mapping_keys && i > (p_int)max_mapping_keys) - ERRORF(("Illegal mapping size: %ld entries\n", (long)i)); + if (max_mapping_size && (p_uint)i * (1+num_values) > (p_uint)max_mapping_size) + ERRORF(("Illegal mapping size: %"PRIuPINT" elements (%u x %u)\n" + , ((p_uint)i * (1+num_values)), i, num_values)); + if (max_mapping_keys && (p_uint)i > (p_uint)max_mapping_keys) + ERRORF(("Illegal mapping size: %u entries\n", i)); /* Get the mapping */ m = allocate_mapping(i, num_values); @@ -15006,8 +15136,8 @@ again: if (n < 0 || n >= m->num_values) { - ERRORF(("Illegal sub-index %ld, mapping width is %ld.\n" - , (long)n, (long)m->num_values)); + ERRORF(("Illegal sub-index %"PRIdMPINT", mapping width is %" + PRIdPINT".\n", n, m->num_values)); } sp--; /* the key */ @@ -15057,8 +15187,8 @@ again: n = sp->u.number; if (n < 0 || n >= m->num_values) { - ERRORF(("Illegal sub-index %ld, mapping width is %ld.\n" - , (long)n, (long)m->num_values)); + ERRORF(("Illegal sub-index %"PRIdMPINT", mapping width is %" + PRIdPINT".\n", n, m->num_values)); } sp--; /* the key */ @@ -15176,12 +15306,13 @@ again: { count = arg->u.number; if (count < 0 && !use_range) - ERRORF(("foreach() got a %ld, expected a non-negative number.", count)); + ERRORF(("foreach() got a %"PRIdPINT", expected a non-negative " + "number.", count)); vars_required = 1; } else if (arg->type == T_STRING) { - count = (p_int)mstrsize(arg->u.str); + count = mstrsize(arg->u.str); vars_required = 1; if (gen_refs) @@ -15210,7 +15341,7 @@ again: else if (arg->type == T_POINTER) { check_for_destr(arg->u.vec); - count = (p_int)VEC_SIZE(arg->u.vec); + count = VEC_SIZE(arg->u.vec); vars_required = 1; if (gen_refs) @@ -15229,7 +15360,7 @@ again: else if (arg->type == T_STRUCT) { struct_check_for_destr(arg->u.strct); - count = (p_int)struct_size(arg->u.strct); + count = struct_size(arg->u.strct); vars_required = 1; if (gen_refs) @@ -15254,7 +15385,7 @@ again: vars_required = 1 + m->num_values; indices = m_indices(m); - count = (p_int)MAP_SIZE(m); + count = MAP_SIZE(m); /* after m_indices(), else we'd count destructed entries */ if (gen_refs) @@ -15369,7 +15500,7 @@ again: mapping_t *m; vector_t *indices; svalue_t *values; - int left; + p_int left; lvalue = sp + sp[-1].x.generic - 2; @@ -15483,7 +15614,7 @@ again: } else if (sp[-2].type == T_POINTER) { - if (ix >= (p_int)VEC_SIZE(sp[-2].u.vec)) + if (ix >= VEC_SIZE(sp[-2].u.vec)) break; /* Oops, this array shrunk while we're looping over it. * We stop processing and continue with the following @@ -15517,7 +15648,7 @@ again: #ifdef USE_STRUCTS else if (sp[-2].type == T_STRUCT) { - if (ix >= (p_int)struct_size(sp[-2].u.strct)) + if (ix >= struct_size(sp[-2].u.strct)) break; /* Oops, somehow the struct managed to shring while * we're looping over it. @@ -15549,10 +15680,14 @@ again: lvalue->u.lvalue = &prot->v; } } -#endif /* USE_STRUCTS */ else - fatal("foreach() requires a string, array or mapping.\n"); - /* If this happens, the check in F_FOREACH failed. */ + fatal("foreach() requires a string, array, struct or mapping.\n"); + /* If this happens, the check in F_FOREACH failed. */ +#else /* USE_STRUCTS */ + else + fatal("foreach() requires a string, array or mapping.\n"); + /* If this happens, the check in F_FOREACH failed. */ +#endif /* USE_STRUCTS */ } /* All that is left is to branch back. */ @@ -15918,7 +16053,7 @@ again: if (sp->type == T_NUMBER) { if (sp->u.number == PINT_MIN) - ERRORF(("Numeric overflow: - %ld\n", sp->u.number)); + ERRORF(("Numeric overflow: - %"PRIdPINT"\n", sp->u.number)); sp->u.number = - sp->u.number; break; } @@ -15964,11 +16099,10 @@ again: * catch(), that catch expression will return arg as error code. */ - assign_eval_cost(); - transfer_svalue_no_free(&catch_value, sp--); - inter_sp = sp; + assign_eval_cost_inl(); + inter_sp = --sp; inter_pc = pc; - throw_error(); /* do the longjump, with extra checks... */ + throw_error(sp+1); /* do the longjump, with extra checks... */ break; /* --- Efuns: Strings --- */ @@ -15988,7 +16122,7 @@ again: { i = mstrsize(sp->u.str); free_string_svalue(sp); - put_number(sp, (p_int)i); + put_number(sp, i); break; } if (sp->type == T_NUMBER && sp->u.number == 0) @@ -16012,11 +16146,11 @@ again: * will return 0. */ - long i; + p_int i; if (sp->type == T_STRING) { - i = (long)mstrsize(sp->u.str); + i = mstrsize(sp->u.str); free_svalue(sp); put_number(sp, i); break; @@ -16024,7 +16158,7 @@ again: if (sp->type == T_POINTER) { - i = (long)VEC_SIZE(sp->u.vec); + i = VEC_SIZE(sp->u.vec); free_svalue(sp); put_number(sp, i); break; @@ -16033,7 +16167,7 @@ again: #ifdef USE_STRUCTS if (sp->type == T_STRUCT) { - i = (long)struct_size(sp->u.strct); + i = struct_size(sp->u.strct); free_svalue(sp); put_number(sp, i); break; @@ -16044,7 +16178,7 @@ again: { mapping_t *m = sp->u.map; check_map_for_destr(m); /* Don't count the destructed keys! */ - i = (long)MAP_SIZE(m); + i = MAP_SIZE(m); free_svalue(sp); put_number(sp, i); break; @@ -16141,7 +16275,7 @@ again: { /* --- The normal call other to a single object --- */ - ASSIGN_EVAL_COST + assign_eval_cost_inl(); if (arg[0].type == T_OBJECT) ob = arg[0].u.ob; @@ -16229,7 +16363,7 @@ again: { int i; - ASSIGN_EVAL_COST + assign_eval_cost_inl(); inter_sp = sp; /* Might be clobbered from previous loop */ if (svp->type == T_OBJECT) @@ -16252,9 +16386,9 @@ again: continue; } else - ERRORF(("Bad arg for call_other() at index %ld: " + ERRORF(("Bad arg for call_other() at index %"PRIdMPINT": " "got %s, expected string/object\n" - , (long)(svp - arg->u.vec->item) + , (mp_int)(svp - arg->u.vec->item) , typename(svp->type) )); @@ -16497,13 +16631,13 @@ again: /* sp ist just at then end of the stack area */ stack_overflow(sp, fp, pc); } - else if ((long)(sp - VALUE_STACK) > (long)(SIZEOF_STACK - 1)) + else if ((mp_int)(sp - VALUE_STACK) > (mp_int)(SIZEOF_STACK - 1)) { /* When we come here, we already overwrote the bounds * of the stack :-( */ - fatal("Fatal stack overflow: %ld too high\n" - , (long)(sp - VALUE_STACK - (SIZEOF_STACK - 1)) + fatal("Fatal stack overflow: %"PRIdMPINT" too high\n" + , (mp_int)(sp - VALUE_STACK - (SIZEOF_STACK - 1)) ); } @@ -16511,18 +16645,18 @@ again: if (expected_stack && expected_stack != sp) { fatal( "Bad stack after evaluation.\n" - "sp: %lx expected: %lx\n" + "sp: %p expected: %p\n" "Instruction %d(%s), num arg %d\n" - , (long)sp, (long)expected_stack + , sp, expected_stack , instruction, get_f_name(instruction), num_arg); } if (sp < fp + csp->num_local_variables - 1) { fatal( "Bad stack after evaluation.\n" - "sp: %lx minimum expected: %lx\n" + "sp: %p minimum expected: %p\n" "Instruction %d(%s), num arg %d\n" - , (long)sp, (long)(fp + csp->num_local_variables - 1) + , sp, (fp + csp->num_local_variables - 1) , instruction, get_f_name(instruction), num_arg); } #endif /* DEBUG */ @@ -17113,7 +17247,7 @@ apply (string_t *fun, object_t *ob, int num_arg) } /* apply() */ /*-------------------------------------------------------------------------*/ -static void +void secure_apply_error ( svalue_t *save_sp, struct control_stack *save_csp , Bool clear_costs) @@ -17241,22 +17375,31 @@ secure_apply_error ( svalue_t *save_sp, struct control_stack *save_csp /*-------------------------------------------------------------------------*/ svalue_t * -secure_apply (string_t *fun, object_t *ob, int num_arg) +secure_apply_ob (string_t *fun, object_t *ob, int num_arg, Bool external) -/* Call function in ject with arguments pushed +/* Aliases: + * secure_apply(fun, ob, num_arg) == secure_apply_ob(fun, ob, num_arg, FALSE) + * secure_callback(fun, ob, num_arg) == secure_apply_ob(fun, ob, num_arg, TRUE) + * + * Call function in ject with arguments pushed * onto the stack ( points to the last one). static and protected * functions can't be called from the outside. - * secure_apply() takes care of calling shadows where necessary. + * secure_apply_ob() takes care of calling shadows where necessary. * - * secure_apply() returns a pointer to the function result when the call was - * successfull, or NULL on failure. The arguments are popped in any case. + * If is TRUE, it means that this call is due to some external + * event (like an ERQ message) instead of being caused by a running program. + * The effect of this flag is that the error handling is like for a normal + * function call (clearing the eval costs before calling runtime_error()). + * + * secure_apply_ob() returns a pointer to the function result when the call + * was successfull, or NULL on failure. The arguments are popped in any case. * The result pointer, if returned, points to a static area which will be - * overwritten with the next secure_apply(). + * overwritten with the next secure_apply_ob(). * * The function call will swap in the object and also unset its reset status. * * Errors during the execution are caught (this is the big difference - * to sapply()/apply()) and cause secure_apply() to return NULL. + * to sapply()/apply()) and cause secure_apply_ob() to return NULL. */ { @@ -17270,12 +17413,12 @@ secure_apply (string_t *fun, object_t *ob, int num_arg) error_recovery_info.rt.last = rt_context; error_recovery_info.rt.type = ERROR_RECOVERY_APPLY; - rt_context = (rt_context_t *)&error_recovery_info; + rt_context = (rt_context_t *)&error_recovery_info.rt; save_sp = inter_sp; save_csp = csp; if (setjmp(error_recovery_info.con.text)) { - secure_apply_error(save_sp - num_arg, save_csp, MY_FALSE); + secure_apply_error(save_sp - num_arg, save_csp, external); result = NULL; } else @@ -17284,7 +17427,7 @@ secure_apply (string_t *fun, object_t *ob, int num_arg) } rt_context = error_recovery_info.rt.last; return result; -} /* secure_apply() */ +} /* secure_apply_ob() */ /*-------------------------------------------------------------------------*/ svalue_t * @@ -17351,7 +17494,7 @@ apply_master_ob (string_t *fun, int num_arg, Bool external) /* Setup the the error recovery and call the function */ error_recovery_info.rt.last = rt_context; error_recovery_info.rt.type = ERROR_RECOVERY_APPLY; - rt_context = (rt_context_t *)&error_recovery_info; + rt_context = (rt_context_t *)&error_recovery_info.rt; save_sp = inter_sp; save_csp = csp; if (setjmp(error_recovery_info.con.text)) @@ -17431,8 +17574,6 @@ assert_master_ob_loaded (void) if (!destructed_master_ob) { - fprintf(stderr, "%s Failed to load master object '%s'.\n" - , time_stamp(), master_name); #ifdef USE_LDMUD_COMPATIBILITY /* What's the purpose of some random english text on * a socket? To inform the archwiz who just killed the master? @@ -17441,7 +17582,11 @@ assert_master_ob_loaded (void) add_message("Failed to load master object '%s'!\n" , master_name); #endif - exit(1); + // fatal() may call us again. But fatal() and this function + // are secured against recursion so it should be safe to call + // it from here (otherwise we would not get a core dump...). + fatal("Failed to load master object '%s'!\n", + master_name); } /* If we come here, we had a destructed master and failed @@ -17706,8 +17851,6 @@ int_call_lambda (svalue_t *lsvp, int num_arg, Bool allowRefs) case CLOSURE_LFUN: /* --- lfun closure --- */ { - funflag_t flags; - fun_hdr_p funstart; Bool extra_frame; /* Can't call from a destructed object */ @@ -17715,9 +17858,7 @@ int_call_lambda (svalue_t *lsvp, int num_arg, Bool allowRefs) { /* inter_sp == sp */ CLEAN_CSP - errorf("Object '%s' the closure was bound to has been " - "destructed\n", get_txt(l->ob->name)); - /* NOTREACHED */ + push_number(inter_sp, 0); return; } @@ -17733,9 +17874,7 @@ int_call_lambda (svalue_t *lsvp, int num_arg, Bool allowRefs) { /* inter_sp == sp */ CLEAN_CSP - errorf("Object '%s' holding the closure has been " - "destructed\n", get_txt(l->function.lfun.ob->name)); - /* NOTREACHED */ + push_number(inter_sp, 0); return; } @@ -17796,14 +17935,12 @@ int_call_lambda (svalue_t *lsvp, int num_arg, Bool allowRefs) current_object = l->function.lfun.ob; current_prog = current_object->prog; /* inter_sp == sp */ - flags = setup_new_frame(l->function.lfun.index, l->function.lfun.inhProg); + setup_new_frame(l->function.lfun.index, l->function.lfun.inhProg); #ifdef USE_NEW_INLINES if (l->function.lfun.context_size > 0) inter_context = l->context; #endif /* USE_NEW_INLINES */ - funstart = current_prog->program + (flags & FUNSTART_MASK); - csp->funstart = funstart; - eval_instruction(FUNCTION_CODE(funstart), inter_sp); + eval_instruction(FUNCTION_CODE(csp->funstart), inter_sp); /* If l->ob selfdestructs during the call, l might have been * deallocated at this point! @@ -17832,9 +17969,7 @@ int_call_lambda (svalue_t *lsvp, int num_arg, Bool allowRefs) /* Don't use variables in a destructed object */ if (l->ob->flags & O_DESTRUCTED) { - errorf("Object '%s' the closure was bound to has been destructed\n" - , get_txt(l->ob->name)); - /* NOTREACHED */ + push_number(inter_sp, 0); return; } @@ -17892,9 +18027,7 @@ int_call_lambda (svalue_t *lsvp, int num_arg, Bool allowRefs) { /* inter_sp == sp */ CLEAN_CSP - errorf("Object '%s' the closure was bound to has been " - "destructed\n", get_txt(l->ob->name)); - /* NOTREACHED */ + push_number(inter_sp, 0); return; } @@ -17951,9 +18084,7 @@ int_call_lambda (svalue_t *lsvp, int num_arg, Bool allowRefs) { /* inter_sp == sp */ CLEAN_CSP - errorf("Object '%s' the closure was bound to has been " - "destructed\n", get_txt(current_object->name)); - /* NOTREACHED */ + push_number(inter_sp, 0); return; } @@ -17986,8 +18117,7 @@ int_call_lambda (svalue_t *lsvp, int num_arg, Bool allowRefs) * the closure should be zeroed out. */ CLEAN_CSP - errorf("Object the closure was bound to has been destructed (this shouldn't happen)\n"); - /* NOTREACHED */ + push_number(inter_sp, 0); return; } @@ -18155,7 +18285,7 @@ secure_call_lambda (svalue_t *closure, int num_arg, Bool external) error_recovery_info.rt.last = rt_context; error_recovery_info.rt.type = ERROR_RECOVERY_APPLY; - rt_context = (rt_context_t *)&error_recovery_info; + rt_context = (rt_context_t *)&error_recovery_info.rt; save_sp = inter_sp; save_csp = csp; @@ -18199,11 +18329,11 @@ call_simul_efun (unsigned int code, object_t *ob, int num_arg) /* Function not found: try the alternative sefun objects */ if (simul_efun_vector) { - long i; + p_int i; svalue_t *v; - i = (long)VEC_SIZE(simul_efun_vector); - for (v = simul_efun_vector->item+1; MY_TRUE; v++) + i = VEC_SIZE(simul_efun_vector); + for (v = simul_efun_vector->item+1 ; ; v++) { if (--i <= 0 || v->type != T_STRING) { @@ -18238,9 +18368,6 @@ call_function (program_t *progp, int fx) */ { - funflag_t flags; - fun_hdr_p funstart; - #ifdef USE_NEW_INLINES push_control_stack(inter_sp, inter_pc, inter_fp, inter_context); #else @@ -18254,12 +18381,10 @@ call_function (program_t *progp, int fx) #endif csp->num_local_variables = 0; current_prog = progp; - flags = setup_new_frame(fx, NULL); - funstart = current_prog->program + (flags & FUNSTART_MASK); - csp->funstart = funstart; + setup_new_frame(fx, NULL); previous_ob = current_object; tracedepth = 0; - eval_instruction(FUNCTION_CODE(funstart), inter_sp); + eval_instruction(FUNCTION_CODE(csp->funstart), inter_sp); free_svalue(inter_sp--); /* Throw away the returned result */ } /* call_function() */ @@ -18290,7 +18415,7 @@ get_line_number (bytecode_p p, program_t *progp, string_t **namep) int super_line; /* Line number within parent file */ }; - int offset; /* (Remaining) program offset to resolve */ + p_int offset; /* (Remaining) program offset to resolve */ int i; /* Current line number */ include_t *includes; /* Pointer to the next include info */ struct incinfo *inctop = NULL; /* The include information stack. */ @@ -18336,15 +18461,16 @@ get_line_number (bytecode_p p, program_t *progp, string_t **namep) #endif /* Get the offset within the program */ - offset = (int)(p - progp->program); + offset = (p - progp->program); if (p < progp->program || p > PROGRAM_END(*progp)) { #ifdef VERBOSE - printf("%s get_line_number(): Illegal offset %d in object %s\n" + printf("%s get_line_number(): Illegal offset %"PRIdPINT" in object %s\n" , time_stamp(), offset, get_txt(progp->name)); #endif - debug_message("%s get_line_number(): Illegal offset %d in object %s\n" - , time_stamp(), offset, get_txt(progp->name)); + debug_message("%s get_line_number(): Illegal offset %"PRIdPINT + " in object %s\n", + time_stamp(), offset, get_txt(progp->name)); *namep = ref_mstring(STR_UNDEFINED); return 0; } @@ -18587,14 +18713,13 @@ get_line_number_if_any (string_t **name) string_t * location, *tmp; lambda_t * l; - sprintf(name_buffer, "", (long)csp->funstart); + sprintf(name_buffer, "", csp->funstart); memsafe(*name = new_mstring(name_buffer), strlen(name_buffer) , "lambda name"); - l = NULL; - l = (lambda_t *)((unsigned long)(csp->funstart) - - ((char *)&(l->function.code) - (char *)l) - - 1 - ); + /* Find the beginning of the lambda structure.*/ + l = (lambda_t *)( (PTRTYPE)(csp->funstart - 1) + - offsetof(lambda_t, function.code)); + location = closure_location(l); tmp = mstr_add(*name, location); @@ -18608,7 +18733,7 @@ get_line_number_if_any (string_t **name) } return get_line_number(inter_pc, current_prog, name); } - + *name = ref_mstring(STR_EMPTY); return 0; } /* get_line_number_if_any() */ @@ -18650,7 +18775,14 @@ collect_trace (strbuf_t * sbuf, vector_t ** rvec ) } *first_entry, *last_entry; size_t num_entries; -#define NEW_ENTRY(var, type, progname) \ +#ifdef EVAL_COST_TRACE +#define PUT_EVAL_COST(var, cost) \ + put_number(var->vec->item+TRACE_EVALCOST, cost); +#else +#define PUT_EVAL_COST(var, cost) +#endif + +#define NEW_ENTRY(var, type, progname, cost) \ struct traceentry * var; \ var = alloca(sizeof(*var)); \ if (!var) \ @@ -18666,7 +18798,8 @@ collect_trace (strbuf_t * sbuf, vector_t ** rvec ) num_entries++; \ put_number(var->vec->item+TRACE_TYPE, type); \ put_ref_string(var->vec->item+TRACE_PROGRAM, progname); \ - put_ref_string(entry->vec->item+TRACE_OBJECT, ob->name); + put_ref_string(entry->vec->item+TRACE_OBJECT, ob->name); \ + PUT_EVAL_COST(var, cost) #define PUT_LOC(entry, val) \ put_number(entry->vec->item+TRACE_LOC, (p_int)(val)) @@ -18714,6 +18847,9 @@ collect_trace (strbuf_t * sbuf, vector_t ** rvec ) do { bytecode_p dump_pc; /* the frame's pc */ program_t *prog; /* the frame's program */ +#ifdef EVAL_COST_TRACE + int32 dump_eval_cost; /* The eval cost at that frame. */ +#endif /* Note: Under certain circumstances the value of file carried over * from the previous iteration is reused in this one. @@ -18745,11 +18881,17 @@ collect_trace (strbuf_t * sbuf, vector_t ** rvec ) { dump_pc = pc; prog = current_prog; +#ifdef EVAL_COST_TRACE + dump_eval_cost = eval_cost; +#endif } else { dump_pc = p[1].pc; prog = p[1].prog; +#ifdef EVAL_COST_TRACE + dump_eval_cost = p[1].eval_cost; +#endif } /* Use some heuristics first to see if it could possibly be a CATCH. @@ -18801,11 +18943,16 @@ not_catch: /* The frame does not point at a catch here */ * TODO:: should never be reached. */ if (sbuf) +#ifndef EVAL_COST_TRACE strbuf_addf(sbuf, " in '%20s' ('%20s')\n" +#else + strbuf_addf(sbuf, "%8d in '%20s' ('%20s')\n" + , dump_eval_cost +#endif , get_txt(ob->prog->name), get_txt(ob->name)); if (rvec) { - NEW_ENTRY(entry, TRACE_TYPE_SYMBOL, ob->prog->name); + NEW_ENTRY(entry, TRACE_TYPE_SYMBOL, ob->prog->name, dump_eval_cost); } continue; } @@ -18815,11 +18962,16 @@ not_catch: /* The frame does not point at a catch here */ { if (sbuf) strbuf_addf( sbuf +#ifndef EVAL_COST_TRACE , " bound to '%20s' ('%20s')\n" +#else + , "%8d bound to '%20s' ('%20s')\n" + , dump_eval_cost +#endif , get_txt(ob->prog->name), get_txt(ob->name)); if (rvec) { - NEW_ENTRY(entry, TRACE_TYPE_SEFUN, ob->prog->name); + NEW_ENTRY(entry, TRACE_TYPE_SEFUN, ob->prog->name, dump_eval_cost); } continue; } @@ -18833,14 +18985,19 @@ not_catch: /* The frame does not point at a catch here */ if (iname) { if (sbuf) +#ifndef EVAL_COST_TRACE strbuf_addf(sbuf, "#\'%-14s for '%20s' ('%20s')\n" +#else + strbuf_addf(sbuf, "%8d #\'%-14s for '%20s' ('%20s')\n" + , dump_eval_cost +#endif , iname, get_txt(ob->prog->name) , get_txt(ob->name)); if (rvec) { string_t *tmp; - NEW_ENTRY(entry, TRACE_TYPE_EFUN, ob->prog->name); + NEW_ENTRY(entry, TRACE_TYPE_EFUN, ob->prog->name, dump_eval_cost); memsafe(tmp = new_mstring(iname), strlen(iname) , "instruction name"); put_string(entry->vec->item+TRACE_NAME, tmp); @@ -18849,12 +19006,17 @@ not_catch: /* The frame does not point at a catch here */ else { if (sbuf) +#ifndef EVAL_COST_TRACE strbuf_addf( sbuf, " for '%20s' ('%20s')\n" +#else + strbuf_addf( sbuf, "%8d for '%20s' ('%20s')\n" + , dump_eval_cost +#endif , p[0].instruction, get_txt(ob->prog->name) , get_txt(ob->name)); if (rvec) { - NEW_ENTRY(entry, TRACE_TYPE_EFUN, ob->prog->name); + NEW_ENTRY(entry, TRACE_TYPE_EFUN, ob->prog->name, dump_eval_cost); put_number(entry->vec->item+TRACE_NAME, p[0].instruction); } } @@ -18867,7 +19029,12 @@ not_catch: /* The frame does not point at a catch here */ { if (sbuf) strbuf_addf( sbuf +#ifndef EVAL_COST_TRACE , " in '%20s' ('%20s') offset %ld\n" +#else + , "%8d in '%20s' ('%20s') offset %ld\n" + , dump_eval_cost +#endif , (long)p[0].funstart , get_txt(ob->prog->name) , get_txt(ob->name) @@ -18875,7 +19042,7 @@ not_catch: /* The frame does not point at a catch here */ ); if (rvec) { - NEW_ENTRY(entry, TRACE_TYPE_LAMBDA, ob->prog->name); + NEW_ENTRY(entry, TRACE_TYPE_LAMBDA, ob->prog->name, dump_eval_cost); put_number(entry->vec->item+TRACE_NAME, (p_int)p[0].funstart); PUT_LOC(entry, (FUNCTION_FROM_CODE(dump_pc) - p[0].funstart)); } @@ -18898,17 +19065,27 @@ name_computed: /* Jump target from the catch detection */ if (sbuf) { if (file != NULL) +#ifndef EVAL_COST_TRACE strbuf_addf(sbuf, "'%15s' in '%20s' ('%20s') line %d\n" +#else + strbuf_addf(sbuf, "%8d '%15s' in '%20s' ('%20s') line %d\n" + , dump_eval_cost +#endif , get_txt(name), get_txt(file) , get_txt(ob->name), line); else +#ifndef EVAL_COST_TRACE strbuf_addf(sbuf, "'%15s' in %22s ('%20s')\n" +#else + strbuf_addf(sbuf, "%8d '%15s' in %22s ('%20s')\n" + , dump_eval_cost +#endif , get_txt(name), "", get_txt(ob->name)); } if (rvec) { - NEW_ENTRY(entry, TRACE_TYPE_LFUN, file != NULL ? file : STR_EMPTY); + NEW_ENTRY(entry, TRACE_TYPE_LFUN, file != NULL ? file : STR_EMPTY, dump_eval_cost); put_ref_string(entry->vec->item+TRACE_NAME, name); PUT_LOC(entry, line); } @@ -18979,8 +19156,8 @@ dump_trace (Bool how, vector_t ** rvec) #ifdef DEBUG (void)last_instructions(200, MY_TRUE, NULL); if (inter_pc) - printf("%6lx: %3d %3d %3d %3d %3d %3d %3d %3d\n" - , (long)inter_pc + printf("%6p: %3d %3d %3d %3d %3d %3d %3d %3d\n" + , inter_pc , inter_pc[0], inter_pc[1], inter_pc[2], inter_pc[3] , inter_pc[4], inter_pc[5], inter_pc[6], inter_pc[7] ); else @@ -19016,7 +19193,7 @@ invalidate_apply_low_cache (void) { int i; - + for (i = 0; i < CACHE_SIZE; i++) { cache[i].id = 0; @@ -19173,7 +19350,7 @@ get_arg (int a) */ { - static char buff[10]; + static char buff[12]; bytecode_p from, to; int b; @@ -19186,7 +19363,7 @@ get_arg (int a) if (to - from == 2) { - sprintf(buff, "%d", GET_CODE(from+1)); + snprintf(buff, sizeof(buff), "%d", GET_CODE(from+1)); return buff; } @@ -19195,7 +19372,7 @@ get_arg (int a) short arg; GET_SHORT(arg, from+1); - sprintf(buff, "%d", arg); + snprintf(buff, sizeof(buff), "%hd", arg); return buff; } @@ -19204,7 +19381,7 @@ get_arg (int a) int32 arg; GET_INT32(arg, from+1); - sprintf(buff, "%ld", (long)arg); + snprintf(buff, sizeof(buff), "%"PRId32, arg); return buff; } @@ -19368,7 +19545,7 @@ last_instructions (int length, Bool verbose, svalue_t **svpp) || (old_file && !mstreq(file, old_file)) ) { - sprintf(buf, "%.170s %.160s line %d" + snprintf(buf, sizeof(buf), "%.170s %.160s line %d" , get_txt(previous_objects[i]->name) , get_txt(file), line ); @@ -19382,16 +19559,16 @@ last_instructions (int length, Bool verbose, svalue_t **svpp) if (file) free_mstring(file); } - sprintf(buf, "%6lx: %3d %8s %-26s (%ld:%3ld)" - , (long)previous_pc[i] + snprintf(buf, sizeof(buf)-40, "%6p: %3d %8s %-26s (%td:%3td)" + , previous_pc[i] , previous_instruction[i] /* instrs.h has these numbers */ , get_arg(i) , get_f_name(previous_instruction[i]) - , (long) (stack_size[i] + 1) - , (long) (abs_stack_size[i]) + , (stack_size[i] + 1) + , (abs_stack_size[i]) ); if (verbose && line != old_line) - sprintf(buf + strlen(buf), "\tline %d", old_line = line); + snprintf(buf + strlen(buf), 40, "\tline %d", old_line = line); last_instr_output(buf, svpp); } } while (i != last); @@ -19439,7 +19616,7 @@ f_last_instructions (svalue_t *sp) /* Test the arguments */ num_instr = sp[-1].u.number; if (num_instr <= 0) - errorf("Illegal number of instructions: %ld.\n", num_instr); + errorf("Illegal number of instructions: %"PRIdMPINT".\n", num_instr); sp--; inter_sp = sp; /* Out of memory possible */ @@ -19476,10 +19653,48 @@ f_last_instructions (svalue_t *sp) #endif /* TRACE_CODE */ +/*-------------------------------------------------------------------------*/ +int control_stack_depth (void) + /* Returns the number of frames on the control stack. Can be used to estimate + * the still available stack depth in recursive code. + */ +{ + return (csp - CONTROL_STACK) + 1; +} /* control_stack_depth() */ + +/*-------------------------------------------------------------------------*/ +static INLINE int +caller_stack_depth(void) +/* static helper function for f_caller_stack_depth() and f_caller_stack() for + * calculating the stack depth. It is a separate function because the code + * is used at two places and the compiler will probably inline it anyway. + */ +{ + int depth; + Bool done; + struct control_stack *p; + + /* Determine the depth of the call stack */ + p = csp; + for (depth = 0, done = MY_FALSE; ; depth++) + { + do { + if (p == CONTROL_STACK) + { + done = MY_TRUE; + break; + } + } while ( !(--p)[1].extern_call ); + if (done) + break; + } + + return depth; +} /* caller_stack_depth() */ + /*-------------------------------------------------------------------------*/ svalue_t * f_caller_stack_depth (svalue_t *sp) - /* EFUN caller_stack_depth() * * int caller_stack_depth(void) @@ -19489,26 +19704,7 @@ f_caller_stack_depth (svalue_t *sp) */ { - int depth; - Bool done; - struct control_stack *p; - - /* Determine the depth of the call stack */ - p = csp; - for (depth = 0, done = MY_FALSE; ; depth++) - { - do { - if (p == CONTROL_STACK) - { - done = MY_TRUE; - break; - } - } while ( !(--p)[1].extern_call ); - if (done) - break; - } - - push_number(sp, depth); + push_number(sp, caller_stack_depth()); return sp; } /* f_caller_stack_depth() */ @@ -19539,20 +19735,8 @@ f_caller_stack (svalue_t *sp) svalue_t *svp; /* Determine the depth of the call stack */ - p = csp; - for (depth = 0, done = MY_FALSE; ; depth++) - { - do { - if (p == CONTROL_STACK) - { - done = MY_TRUE; - break; - } - } while ( !(--p)[1].extern_call ); - if (done) - break; - } - + depth = caller_stack_depth(); + /* Allocate and fill in the result array */ v = allocate_uninit_array(depth + (sp->u.number ? 1 : 0)); p = csp; @@ -19694,8 +19878,9 @@ count_inherits (program_t *progp) progp2 = progp->inherit[i].prog; progp2->extra_ref++; if (progp2 == check_a_lot_ref_counts_search_prog) - printf("%s Found prog, inherited by %s, new total ref %ld\n" - , time_stamp(), get_txt(progp->name), progp2->ref); + printf("%s Found prog, inherited by %s, new total ref %" + PRIdPINT"\n", + time_stamp(), get_txt(progp->name), progp2->ref); if (NULL == register_pointer(ptable, progp2)) { continue; @@ -20028,7 +20213,8 @@ check_a_lot_ref_counts (program_t *search_prog) { if (ob->flags & O_DESTRUCTED) { - /* This shouldn't happen */ + /* This shouldn't happen + * TODO: remove check? enclose in #ifdef DEBUG? */ debug_message("%s Found destructed object '%s' where it shouldn't " "be.\n", time_stamp(), get_txt(ob->name)); continue; @@ -20109,8 +20295,8 @@ check_a_lot_ref_counts (program_t *search_prog) if (ob->ref != ob->extra_ref) { - debug_message("%s Bad ref count in object %s: listed %ld - " - "counted %ld\n" + debug_message("%s Bad ref count in object %s: listed %" + PRIdPINT" - counted %"PRIdPINT"\n" , time_stamp(), get_txt(ob->name) , ob->ref, ob->extra_ref); } else @@ -20124,7 +20310,7 @@ check_a_lot_ref_counts (program_t *search_prog) && ob->prog->ref > ob->prog->extra_ref) { debug_message("%s high ref count in prog %s: " - "listed %ld - counted %ld\n" + "listed %"PRIdPINT" - counted %"PRIdPINT"\n" , time_stamp() , get_txt(ob->prog->name), ob->prog->ref , ob->prog->extra_ref); @@ -20132,8 +20318,8 @@ check_a_lot_ref_counts (program_t *search_prog) else { check_a_lot_ref_counts(ob->prog); - debug_message("%s Bad ref count in prog %s: listed %ld - " - "counted %ld\n" + debug_message("%s Bad ref count in prog %s: " + "listed %"PRIdPINT" - counted %"PRIdPINT"\n" , time_stamp() , get_txt(ob->prog->name) , ob->prog->ref, ob->prog->extra_ref); @@ -20142,7 +20328,7 @@ check_a_lot_ref_counts (program_t *search_prog) #ifdef USE_SWAP } /* !SWAPPED */ #endif - check_extra_ref_in_vector(ob->variables, (size_t)ob->extra_num_variables); + check_extra_ref_in_vector(ob->variables, ob->extra_num_variables); } /* for */ check_extra_ref_in_vector(VALUE_STACK, (size_t)(inter_sp - VALUE_STACK + 1)); @@ -20222,8 +20408,8 @@ v_apply (svalue_t *sp, int num_arg) case CLOSURE_BOUND_LAMBDA: if (num_arg + (sp - VALUE_STACK) < EVALUATOR_STACK_SIZE) break; - errorf("VM Stack overflow: %ld too high.\n" - , (long)(num_arg + (sp - VALUE_STACK) - EVALUATOR_STACK_SIZE) ); + errorf("VM Stack overflow: %zu too high.\n", + (size_t)(num_arg + (sp - VALUE_STACK) - EVALUATOR_STACK_SIZE) ); break; } @@ -20495,7 +20681,7 @@ f_get_eval_cost (svalue_t *sp) */ { - push_number(sp, (max_eval_cost ? max_eval_cost : LONG_MAX) - eval_cost); + push_number(sp, (max_eval_cost ? max_eval_cost : PINT_MAX) - eval_cost); return sp; } /* f_get_eval_cost() */ @@ -20611,7 +20797,7 @@ f_trace (svalue_t *sp) { svalue_t *arg; - assign_eval_cost(); + assign_eval_cost_inl(); inter_sp = sp; push_ref_string(inter_sp, STR_TRACE); push_number(inter_sp, sp->u.number); @@ -20668,7 +20854,7 @@ f_traceprefix (svalue_t *sp) inter_sp = sp; push_ref_string(inter_sp, STR_TRACEPREFIX); inter_sp++; assign_svalue_no_free(inter_sp, sp); - assign_eval_cost(); + assign_eval_cost_inl(); arg = apply_master(STR_VALID_TRACE,2); if (arg) { diff --git a/src/interpret.h b/src/interpret.h index 157649d..6db6df4 100644 --- a/src/interpret.h +++ b/src/interpret.h @@ -78,23 +78,28 @@ struct control_stack { * TODO: This should be mirrored in the current_object global variable, * TODO:: to avoid accesses to wrong functions/variables. */ +#ifdef EVAL_COST_TRACE + int32 eval_cost; + /* The eval cost at that moment. */ +#endif }; -/* --- Macros --- */ +/* a general error handler structure. head is assigned as payload to an + * T_LVALUE svalue of type T_ERROR_HANDLER and pushed onto the value stack. + * If the stack is unrolled during runtime errors the error_handler function + * is called and frees buff. */ +typedef struct errorhandler_s { + svalue_t head; /* The T_ERROR_HANDLER structure */ + char * buff; /* The allocated buffer to free. */ +} errorhandler_t; -#define MAX_SHIFT ((sizeof(p_int) << 3) - 1) + +/* --- Constants --- */ + +static const short MAX_SHIFT = (sizeof(p_int) << 3) - 1; /* The maximally useful shift (left or right) of a number in LPC. */ -/* Reset the evaluation cost/time counter. - */ -#define CLEAR_EVAL_COST (assigned_eval_cost = eval_cost = 0) - -/* Check if the current evaluation took too long - */ -#define EVALUATION_TOO_LONG() \ - (max_eval_cost && (eval_cost >= max_eval_cost || eval_cost < 0)) - /* --- Variables --- */ extern program_t *current_prog; @@ -108,12 +113,11 @@ extern svalue_t *current_variables; extern int32 eval_cost; extern int32 assigned_eval_cost; extern svalue_t apply_return_value; -extern svalue_t catch_value; extern svalue_t last_indexing_protector; #ifdef APPLY_CACHE_STAT -extern p_int apply_cache_hit; -extern p_int apply_cache_miss; +extern p_uint apply_cache_hit; +extern p_uint apply_cache_miss; #endif extern unsigned long total_evalcost; @@ -138,7 +142,8 @@ extern void push_control_stack(svalue_t *sp, bytecode_p pc, svalue_t *fp); extern void pop_control_stack(void); extern struct longjump_s *push_error_context(svalue_t *sp, int catch_flags); extern void pop_error_context (void); -extern svalue_t *pull_error_context (svalue_t *sp); +extern svalue_t *pull_error_context (svalue_t *sp, svalue_t *msg); +extern void transfer_error_message (svalue_t *v, rt_context_t *rt); extern Bool destructed_object_ref (svalue_t *svp); extern void free_object_svalue(svalue_t *v); extern void zero_object_svalue(svalue_t *v); @@ -156,6 +161,11 @@ extern void push_svalue(svalue_t *v); extern void push_svalue_block(int num, svalue_t *v); extern svalue_t *pop_n_elems (int n, svalue_t *sp); extern void pop_stack(void); +extern void push_apply_value(void); +extern void pop_apply_value (void); +extern void push_referenced_mapping(mapping_t *m); +extern svalue_t *push_error_handler(void (*errorhandler)(svalue_t *), svalue_t *arg); +extern void *xalloc_with_error_handler(size_t size); extern void init_interpret(void); extern const char *typename(int type); @@ -170,8 +180,7 @@ extern void vefun_exp_arg_error (int arg, long expected, int got, svalue_t *sp) extern Bool privilege_violation(string_t *what, svalue_t *arg, svalue_t *sp); extern Bool privilege_violation2(string_t *what, svalue_t *arg, svalue_t *arg2, svalue_t *sp); extern Bool privilege_violation4(string_t *what, object_t *whom, string_t *how_str, int how_num, svalue_t *sp); -extern void push_apply_value(void); -extern void pop_apply_value (void); + extern svalue_t *sapply_int(string_t *fun, object_t *ob, int num_arg, Bool b_ign_prot, Bool b_use_default); #define sapply(f,o,n) sapply_int(f,o,n, MY_FALSE, MY_TRUE) #define sapply_ign_prot(f,o,n) sapply_int(f,o,n, MY_TRUE, MY_TRUE) @@ -182,7 +191,11 @@ extern string_t *collect_trace(strbuf_t * sbuf, vector_t ** rvec); extern string_t *dump_trace(Bool how, vector_t **rvec); extern int get_line_number_if_any(string_t **name); extern void reset_machine(Bool first); -extern svalue_t *secure_apply(string_t *fun, object_t *ob, int num_arg); +extern void secure_apply_error(svalue_t *save_sp, struct control_stack *save_csp, Bool clear_costs); +extern svalue_t *secure_apply_ob(string_t *fun, object_t *ob, int num_arg, Bool external); +#define secure_apply(fun, ob, num_arg) secure_apply_ob(fun, ob, num_arg, MY_FALSE) +#define secure_callback(fun, ob, num_arg) secure_apply_ob(fun, ob, num_arg, MY_TRUE) + extern svalue_t *apply_master_ob(string_t *fun, int num_arg, Bool external); #define apply_master(fun, num_arg) apply_master_ob(fun, num_arg, MY_FALSE) #define callback_master(fun, num_arg) apply_master_ob(fun, num_arg, MY_TRUE) @@ -198,12 +211,9 @@ extern void int_call_lambda(svalue_t *lsvp, int num_arg, Bool allowRefs); extern inherit_t *adjust_variable_offsets(const inherit_t *inheritp, const program_t *prog, const object_t *obj); extern void free_interpreter_temporaries(void); extern void invalidate_apply_low_cache(void); -extern void push_referenced_mapping(mapping_t *m); -extern void push_error_handler(void (*errorhandler)(svalue_t *), svalue_t *arg); extern void m_indices_filter (svalue_t *key, svalue_t *data, void *extra); extern void m_values_filter (svalue_t *key, svalue_t *data, void *extra); extern void m_unmake_filter ( svalue_t *key, svalue_t *data, void *extra); -extern int last_instructions(int length, Bool verbose, svalue_t **svpp); extern svalue_t *v_apply (svalue_t *sp, int num_arg); extern svalue_t *v_funcall (svalue_t *sp, int num_arg); extern svalue_t *v_call_direct_resolved (svalue_t *sp, int num_arg); @@ -212,7 +222,6 @@ extern svalue_t *f_caller_stack_depth (svalue_t *sp); extern svalue_t *f_caller_stack (svalue_t *sp); extern svalue_t *f_get_eval_cost (svalue_t *sp); extern svalue_t *f_previous_object (svalue_t *sp); -extern svalue_t *f_last_instructions(svalue_t *sp); extern svalue_t *f_set_this_object (svalue_t *sp); extern svalue_t *f_trace(svalue_t *sp); extern svalue_t *f_traceprefix(svalue_t *sp); @@ -222,7 +231,8 @@ extern Bool opcdump(string_t *fname); #endif #ifdef TRACE_CODE -extern int last_instructions(int length, int verbose, svalue_t **svpp); +extern svalue_t *f_last_instructions(svalue_t *sp); +extern int last_instructions(int length, Bool verbose, svalue_t **svpp); #endif #ifdef DEBUG @@ -240,5 +250,6 @@ extern void clear_interpreter_refs(void); extern void count_interpreter_refs(void); #endif +extern int control_stack_depth(void); #endif /* INTERPRET_H__ */ diff --git a/src/lex.c b/src/lex.c index 9db70a4..cbbaa04 100644 --- a/src/lex.c +++ b/src/lex.c @@ -62,6 +62,8 @@ #include "wiz_list.h" /* wizlist_name[] */ #include "xalloc.h" +#include "i-eval_cost.h" + #include "../mudlib/sys/driver_hook.h" /* TODO: Implement the # and ## operators. With this, #define X(a) (a + "a") @@ -795,24 +797,27 @@ init_lexer(void) sprintf(mtext, "%d", ERQ_MAX_REPLY); add_permanent_define("__ERQ_MAX_REPLY__", -1, string_copy(mtext), MY_FALSE); #endif - sprintf(mtext, "%ld", (long)max_malloced); + sprintf(mtext, "%"PRIdMPINT, max_malloced); add_permanent_define("__MAX_MALLOC__", -1, string_copy(mtext), MY_FALSE); - sprintf(mtext, "%ld", (long)def_eval_cost); + sprintf(mtext, "%"PRId32, def_eval_cost); add_permanent_define("__MAX_EVAL_COST__", -1, string_copy(mtext), MY_FALSE); sprintf(mtext, "%ld", (long)CATCH_RESERVED_COST); add_permanent_define("__CATCH_EVAL_COST__", -1, string_copy(mtext), MY_FALSE); sprintf(mtext, "%ld", (long)MASTER_RESERVED_COST); add_permanent_define("__MASTER_EVAL_COST__", -1, string_copy(mtext), MY_FALSE); - sprintf(mtext, "%ld", (long)time_to_reset); + sprintf(mtext, "%ld", time_to_reset); add_permanent_define("__RESET_TIME__", -1, string_copy(mtext), MY_FALSE); - sprintf(mtext, "%ld", (long)time_to_cleanup); + sprintf(mtext, "%ld", time_to_cleanup); add_permanent_define("__CLEANUP_TIME__", -1, string_copy(mtext), MY_FALSE); - sprintf(mtext, "%ld", (long)alarm_time); + sprintf(mtext, "%ld", alarm_time); add_permanent_define("__ALARM_TIME__", -1, string_copy(mtext), MY_FALSE); - sprintf(mtext, "%ld", (long)heart_beat_interval); + sprintf(mtext, "%ld", heart_beat_interval); add_permanent_define("__HEART_BEAT_INTERVAL__", -1, string_copy(mtext), MY_FALSE); if (synch_heart_beats) add_permanent_define("__SYNCHRONOUS_HEART_BEAT__", -1, string_copy("1"), MY_FALSE); +#ifdef EVAL_COST_TRACE + add_permanent_define("__EVAL_COST_TRACE__", -1, string_copy("1"), MY_FALSE); +#endif #ifdef MSDOS_FS add_permanent_define("__MSDOS_FS__", -1, string_copy("1"), MY_FALSE); #endif @@ -834,6 +839,9 @@ init_lexer(void) #ifdef USE_SQLITE add_permanent_define("__SQLITE__", -1, string_copy("1"), MY_FALSE); #endif +#ifdef USE_IKSEMEL + add_permanent_define("__XML_DOM__", -1, string_copy("1"), MY_FALSE); +#endif #ifdef USE_EXPAT add_permanent_define("__EXPAT__", -1, string_copy("1"), MY_FALSE); #endif @@ -892,15 +900,15 @@ init_lexer(void) add_permanent_define("__WIZLIST__", -1, string_copy(mtext), MY_FALSE); } - sprintf(mtext, "(%ld)", PINT_MAX); + sprintf(mtext, "(%"PRIdPINT")", PINT_MAX); add_permanent_define("__INT_MAX__", -1, string_copy(mtext), MY_FALSE); - sprintf(mtext, "(%ld)", PINT_MIN); + sprintf(mtext, "(%"PRIdPINT")", PINT_MIN); add_permanent_define("__INT_MIN__", -1, string_copy(mtext), MY_FALSE); sprintf(mtext, "(%g)", DBL_MAX); add_permanent_define("__FLOAT_MAX__", -1, string_copy(mtext), MY_FALSE); sprintf(mtext, "(%g)", DBL_MIN); add_permanent_define("__FLOAT_MIN__", -1, string_copy(mtext), MY_FALSE); - sprintf(mtext, "%ld", get_current_time()); + sprintf(mtext, "%"PRIdMPINT, get_current_time()); add_permanent_define("__BOOT_TIME__", -1, string_copy(mtext), MY_FALSE); /* Add the permanent macro definitions given on the commandline */ @@ -1925,8 +1933,8 @@ make_global_identifier (char *s, int n) { ip = xalloc(sizeof(ident_t)); if (!ip) { - yyerrorf("Out of memory: identifier (%lu bytes)" - , (unsigned long) sizeof(ident_t)); + yyerrorf("Out of memory: identifier (%zu bytes)", + sizeof(ident_t)); return NULL; } ip->name = ref_mstring(q->name); @@ -2079,8 +2087,8 @@ realloc_defbuf (void) defbuf_len <<= 1; } if (comp_flag) - fprintf(stderr, "%s (reallocating defbuf from %ld (%ld left) to %ld) " - , time_stamp(), (long)old_defbuf_len, (long)(old_outp-defbuf) + fprintf(stderr, "%s (reallocating defbuf from %zu (%td left) to %lu) " + , time_stamp(), old_defbuf_len, (ptrdiff_t)(old_outp-defbuf) , defbuf_len); defbuf = xalloc(defbuf_len); memcpy(defbuf+defbuf_len-old_defbuf_len, old_defbuf, old_defbuf_len); @@ -2604,10 +2612,12 @@ add_auto_include (const char * obj_file, const char *cur_file, Bool sys_include) if (auto_include_string != NULL) { /* The auto include string is handled like a normal include */ - current_loc.line++; /* Make sure to restore to line 1 */ + if (cur_file != NULL) /* Otherwise we already are at line 1 */ + current_loc.line++; /* Make sure to restore to line 1 */ (void)start_new_include(-1, auto_include_string , current_loc.file->name, "auto include", ')'); - current_loc.line++; /* Make sure to start at line 1 */ + if (cur_file == NULL) /* Otherwise #include will increment it */ + current_loc.line++; /* Make sure to start at line 1 */ } } /* add_auto_include() */ @@ -3664,6 +3674,8 @@ parse_numeric_escape (char * cp, unsigned char * p_char) /* strtol() gets the sign bit wrong, * strtoul() isn't portable enough. + * TODO: strtoul should be portable enough today... Re-check if we + * TODO::require C99. */ num_digits = 2; l = 0; @@ -3680,7 +3692,10 @@ parse_numeric_escape (char * cp, unsigned char * p_char) /* Parse a normal number from here */ l = c - '0'; - if (l < 0 || l > base) + /* l is unsigned. So any c smaller than '0' will be wrapped into + * positive values and be larger then base as well. Therefore an + * additional comparison of l < 0 is not explicitly needed here. */ + if (l > base) { yywarn("Character constant used with no valid digits"); return NULL; @@ -3933,8 +3948,8 @@ add_lex_string (char *str, size_t slen) new = mstr_add_txt(last_lex_string, str, slen); if (!new) { - lexerrorf("Out of memory for string concatenation (%lu bytes)" - , (unsigned long)len1+slen); + lexerrorf("Out of memory for string concatenation (%zu bytes)", + len1+slen); } free_mstring(last_lex_string); last_lex_string = make_tabled(new); @@ -3961,8 +3976,8 @@ string (char *str, size_t slen) last_lex_string = new_n_tabled(str, slen); if (!last_lex_string) { - lexerrorf("Out of memory for string literal (%lu bytes)" - , (unsigned long)slen); + lexerrorf("Out of memory for string literal (%zu bytes)", + slen); } } return L_STRING; @@ -4233,7 +4248,7 @@ closure (char *in_yyp) } /* closure() */ /*-------------------------------------------------------------------------*/ -static INLINE char * +static char * handle_preprocessor_statement (char * in_yyp) /* The lexer has found a preprocessor statement (#), an @@ -4647,18 +4662,6 @@ yylex1 (void) current_loc = p->loc; if (!was_string_source) current_loc.line++; - else - { - /* 'string' includes are supposed to be inline - * so correct the line number information to take out - * the assumed newlines. - * This has to be done after store_include_end() - * since that function may remove all line number - * information since the start of the include. - */ - current_loc.line -= 1; - store_line_number_backward(1); - } yyin = p->yyin; saved_char = p->saved_char; @@ -7774,7 +7777,7 @@ show_lexer_status (strbuf_t * sbuf, Bool verbose UNUSED) sum += 2 * DEFMAX; /* for the buffers in _expand_define() */ if (sbuf) - strbuf_addf(sbuf, "Lexer structures\t\t\t %9lu\n", sum); + strbuf_addf(sbuf, "Lexer structures\t\t\t %9zu\n", sum); return sum; } /* show_lexer_status() */ @@ -7814,7 +7817,7 @@ count_lex_refs (void) count_ident_refs(id); for (id2 = id->inferior; id2 != NULL; id2 = id2->next) { - count_ident_refs(id); + count_ident_refs(id2); } } } diff --git a/src/lex.h b/src/lex.h index 90da1f7..f0ce893 100644 --- a/src/lex.h +++ b/src/lex.h @@ -240,7 +240,7 @@ struct inline_fun extern struct lpc_predef_s * lpc_predefs; extern int total_lines; extern source_loc_t current_loc; -extern int pragma_strict_types; +extern Bool pragma_strict_types; extern Bool pragma_use_local_scopes; extern Bool pragma_save_types; extern Bool pragma_combine_strings; diff --git a/src/main.c b/src/main.c index 7552e2e..03adff4 100644 --- a/src/main.c +++ b/src/main.c @@ -76,6 +76,12 @@ #include "pkg-mysql.h" #endif +#ifdef USE_IKSEMEL +#include "pkg-iksemel.h" +#endif + +#include "i-eval_cost.h" + #include "../mudlib/sys/regexp.h" /*-------------------------------------------------------------------------*/ @@ -110,8 +116,6 @@ Bool share_variables = MY_FALSE; /* Clones are initialized from their Bool allow_filename_spaces = MY_FALSE; /* Allow spaces in filenames */ -static uint32 random_seed = 0; /* The seed for the pseudo-random generator. */ - static char * hostname = NULL; static char * hostaddr = NULL; /* Hostname and -addr given on the commandline. They are passed as @@ -269,6 +273,7 @@ main (int argc, char **argv) boot_time = (mp_int)time(NULL); setlocale(LC_CTYPE, ""); /* Use the locale defined in the LANG env var */ + setlocale(LC_TIME, ""); get_stack_direction(); mb_init(); init_interpret(); @@ -278,9 +283,15 @@ main (int argc, char **argv) put_number(&const1, 1); current_time = get_current_time(); - random_seed = (uint32)current_time; - seed_random(random_seed); - + + + // Set prng_device_name to the default // + prng_device_name = strdup(PRNG_DEFAULT_DEVICE); + // init PRG by the default device (/dev/urandom) + // if --random-seed or --randomdevice is given on the command-line it + // will re-seeded later. + seed_random(prng_device_name); + do { dummy_current_object_for_loads = NULL_object; #ifdef DEBUG @@ -437,15 +448,6 @@ main (int argc, char **argv) for (i = 0; i < (int)(sizeof avg_consts / sizeof avg_consts[0]); i++) avg_consts[i] = exp(- i / 900.0); -#ifdef USE_LDMUD_COMPATIBILITY -# ifdef VERBOSE - printf("%s Random seed: 0x%lx\n" - , time_stamp(), (unsigned long)random_seed); -# endif - debug_message("%s Random seed: 0x%lx\n" - , time_stamp(), (unsigned long)random_seed); -#endif - #ifdef USE_MYSQL if (!pkg_mysql_init()) { @@ -454,6 +456,10 @@ main (int argc, char **argv) } #endif +#ifdef USE_IKSEMEL + pkg_iksemel_init(); +#endif + /* If the master_name hasn't been set, select a sensible default */ if ('\0' == master_name[0]) { @@ -1064,6 +1070,7 @@ typedef enum OptNumber { , cNoHeart /* --no-heart */ , cNoPreload /* --no-preload */ , cPidFile /* --pidfile */ + , cRandomdevice /* --randomdevice */ , cRandomSeed /* --random-seed */ , cRegexp /* --regexp */ , cResetTime /* --reset-time */ @@ -1506,6 +1513,16 @@ static Option aOptions[] , " Use as the directory where your certificate revocation lists reside.\n" " If relative, is interpreted relative to .\n" } + , { 0, "tls-crlfile", cTLScrlfile, MY_TRUE + , " --tls-crlfile \n" + , " Use as the filename holding your certificate revocation lists.\n" + " If relative, is interpreted relative to .\n" + } + , { 0, "tls-crldirectory", cTLScrldir, MY_TRUE + , " --tls-crldirectory \n" + , " Use as the directory where your certificate revocation lists reside.\n" + " If relative, is interpreted relative to .\n" + } #endif /* USE_TLS */ , { 0, "wizlist-file", cWizlistFile, MY_TRUE @@ -1527,6 +1544,13 @@ static Option aOptions[] " Write the pid of the driver process into .\n" } + , { 0, "randomdevice", cRandomdevice, MY_TRUE + , " --randomdevice \n" + , " --randomdevice \n" + " Determines the source of the seed for the random number generator.\n" + " (tries /dev/urandom by default and uses system clock as fallback)\n" + } + , { 0, "random-seed", cRandomSeed, MY_TRUE , " --random-seed \n" , " --random-seed \n" @@ -1820,6 +1844,9 @@ options (void) #ifdef HAS_IDN , "idna supported\n" #endif +#ifdef USE_IKSEMEL + , "iksemel supported\n" +#endif #ifdef USE_IPV6 , "IPv6 supported\n" #endif @@ -2556,33 +2583,38 @@ eval_arg (int eOption, const char * pValue) } new_mudlib = 1; #ifndef USE_LDMUD_COMPATIBILITY - debug_message("%s Sandboxing myself into %s\n", + debug_message("%s Entering my %s sandbox\n", time_stamp(), pValue); #endif + break; -#if 1 /* def USE_DEBUG_LOG */ case cDebugFile: #ifdef USE_DEBUG_LOG if (debug_file != NULL) free(debug_file); debug_file = strdup(pValue); #else - debug_message("%s Ignoring --debug-file option\n" -/* " This function has been disabled at compile time.\n" - " Please remove it from your scripts.\n" */ - , time_stamp()); + debug_message("%s Ignoring --debug-file option\n", time_stamp()); #endif break; -#endif + + case cRandomdevice: + // sets prng_device_name to some file/device and re-seeds the PRNG + // from it. + if (prng_device_name != NULL) + free(prng_device_name); + prng_device_name = strdup(pValue); + seed_random(prng_device_name); + break; case cRandomSeed: + // seeds PRG with given value #ifdef HAVE_STRTOUL - random_seed = strtoul(pValue, (char **)0, 0); + seed_random_from_int(strtoul(pValue, (char **)0, 0)); #else - random_seed = (uint32)strtol(pValue, (char **)0, 0); + seed_random_from_int((uint32)strtol(pValue, (char **)0, 0)); #endif - seed_random(random_seed); break; case cReserved: @@ -2687,6 +2719,16 @@ eval_arg (int eOption, const char * pValue) } gcollect_outfd = default_gcollect_outfd; break; + case cTLScrlfile: + if (tls_crlfile != NULL) + free(tls_crlfile); + tls_crlfile = strdup(pValue); + break; + case cTLScrldir: + if (tls_crldirectory != NULL) + free(tls_crldirectory); + tls_crldirectory = strdup(pValue); + break; #endif case cOptions: diff --git a/src/main.h b/src/main.h index c2448b4..9212ecf 100644 --- a/src/main.h +++ b/src/main.h @@ -61,7 +61,7 @@ extern int exit_code; extern int main(int argc, char **argv); extern void initialize_master_uid(void); extern void debug_message(const char *, ...) FORMATDEBUG(printf, 1, 2); -extern void vdebug_message(const char *, va_list); +extern void vdebug_message(const char *, va_list) FORMATDEBUG(printf, 1, 0); extern void write_X (int d, unsigned char i); extern void write_x(int d, p_uint i); diff --git a/src/make_func.y b/src/make_func.y index 643337c..3c957d5 100644 --- a/src/make_func.y +++ b/src/make_func.y @@ -485,7 +485,7 @@ static int curr_lpc_type_size = 0; /* Forward declarations */ -static void yyerror(const char *); +static void yyerror(const char *) NORETURN; static int yylex(void); int yyparse(void); int ungetc(int c, FILE *f); @@ -496,7 +496,7 @@ static const char *ctype(int); #ifndef toupper int toupper(int); #endif -static int fatal(const char *str); +static void fatal(const char *str) NORETURN; static int cond_get_exp(int); /*-------------------------------------------------------------------------*/ @@ -517,7 +517,7 @@ mystrdup (const char *str) } /*-------------------------------------------------------------------------*/ -static int +static void fatal (const char *str) /* Print on stderr, flush stdout and exit the program with @@ -528,8 +528,6 @@ fatal (const char *str) fprintf(stderr, "%s", str); fflush(stdout); exit(1); - /* NOTREACHED */ - return 0; } /*-------------------------------------------------------------------------*/ diff --git a/src/mapping.c b/src/mapping.c index b8cfc99..c956bc1 100644 --- a/src/mapping.c +++ b/src/mapping.c @@ -15,6 +15,11 @@ * TODO:: The pool is not absolutely required, but would reduce overhead if * TODO:: MALLOC_TRACE is in effect. * + * TODO: Check if the use of mp_int is reasonable for values for num_values + * TODO::and num_entries (which are in the struct p_int). And check as + * TODO::the wild mixture of mp_int, p_int, size_t (and maybe still int?) + * TODO::used for iterating over mapping structures. + * * Mappings, or 'associative arrays', are similar to normal arrays, with * the principal difference that they can use every value to index their * stored data, whereas arrays only index with integer values. On the @@ -370,7 +375,8 @@ get_new_hash ( mapping_t *m, mp_int hash_size) * * Return the new structure, or NULL when out of memory. */ - +/* TODO: hash_size of mp_int seems unnecessarily large to me, because + * TODO::mappings can only have p_int values? */ { mapping_hash_t *hm; map_chain_t **mcp; @@ -439,7 +445,8 @@ get_new_mapping ( wiz_list_t * user, mp_int num_values * * Return the new mapping, or NULL when out of memory. */ - +/* TODO: hash_size of mp_int seems unnecessarily large to me, because + * TODO::mappings can only have p_int values? */ { mapping_cond_t *cm; mapping_hash_t *hm; @@ -588,7 +595,8 @@ _free_mapping (mapping_t *m, Bool no_data) fatal("No wizlist pointer for mapping"); if (!no_data && m->ref > 0) - fatal("Mapping with %ld refs passed to _free_mapping().\n", m->ref); + fatal("Mapping with %"PRIdPINT" refs passed to _free_mapping().\n", + m->ref); #endif num_mappings--; @@ -624,11 +632,11 @@ _free_mapping (mapping_t *m, Bool no_data) if ( NULL != (hm = m->hash) ) { map_chain_t **mcp, *mc, *next; - int i; + p_int i; #ifdef DEBUG if (hm->ref) - fatal("Ref count in freed hash mapping: %ld\n", hm->ref); + fatal("Ref count in freed hash mapping: %"PRIdPINT"\n", hm->ref); #endif LOG_SUB("free_mapping hash", SIZEOF_MH(hm)); m->user->mapping_total -= SIZEOF_MH(hm); @@ -694,8 +702,9 @@ free_protector_mapping (mapping_t *m) } #endif dump_trace(MY_FALSE, NULL); - printf("%s free_protector_mapping() : no hash %s\n" +/* printf("%s free_protector_mapping() : no hash %s\n" , time_stamp(), m->hash ? "reference" : "part"); + */ free_mapping(m); } #endif /* DEBUG */ @@ -980,13 +989,14 @@ static svalue_t local_const0; } if (max_mapping_size && msize > (mp_int)max_mapping_size) { - errorf("Illegal mapping size: %ld elements (%ld x %ld)\n" - , msize, (long)MAP_SIZE(m)+1, (long)m->num_values); + errorf("Illegal mapping size: %"PRIdMPINT" elements (%" + PRIdPINT" x %"PRIdPINT")\n" + , msize, MAP_SIZE(m)+1, m->num_values); return NULL; } if (max_mapping_keys && MAP_SIZE(m) > (mp_int)max_mapping_keys) { - errorf("Illegal mapping size: %ld entries\n", msize+1); + errorf("Illegal mapping size: %"PRIdMPINT" entries\n", msize+1); return NULL; } } @@ -1188,7 +1198,7 @@ check_map_for_destr (mapping_t *m) */ { - int num_values; + p_int num_values; mapping_cond_t *cm; mapping_hash_t *hm; @@ -1210,7 +1220,7 @@ check_map_for_destr (mapping_t *m) if (destructed_object_ref(entry)) { - int i; + p_int i; svalue_t * data = COND_DATA(cm, ix, num_values); /* Destructed key: remove the whole entry */ @@ -1450,6 +1460,7 @@ resize_mapping (mapping_t *m, mp_int new_width) mapping_hash_t * hm, *hm2 = NULL; mapping_cond_t * cm, *cm2 = NULL; mp_int common_width; /* == min(num_values, new_width) */ + p_int num_entries; /* Set the width variables */ if (m->num_values >= new_width) @@ -1469,12 +1480,14 @@ resize_mapping (mapping_t *m, mp_int new_width) && (SSIZE_MAX - sizeof(map_chain_t)) / new_width < sizeof(svalue_t)) ) { - errorf("Mapping width too big (%ld)\n", new_width); + errorf("Mapping width too big (%"PRIdMPINT")\n", new_width); /* NOTREACHED */ return NULL; } } + + num_entries = m->num_entries; /* Get the target mapping without a hash, but with a condensed block * big enough to hold all entries. @@ -1490,7 +1503,7 @@ resize_mapping (mapping_t *m, mp_int new_width) m2 = get_new_mapping(current_object->user, new_width, 0, cm_size); if (!m2) { - outofmem(sizeof *m2 + sizeof(svalue_t) * m->num_entries * new_width + outofmem(sizeof *m2 + (mp_int)sizeof(svalue_t) * m->num_entries * new_width , "result mapping base structure"); /* NOTREACHED */ return NULL; @@ -1531,39 +1544,42 @@ resize_mapping (mapping_t *m, mp_int new_width) map_chain_t *last = NULL, *mc, *mc2; for (mc = *mcp++; mc; mc = mc->next) - { - svalue_t *src, *dest; - p_int i; - - mc2 = new_map_chain(m2); - if (!mc2) + if(destructed_object_ref(&(mc->data[0]))) + num_entries--; + else { - xfree(hm2); - outofmem(SIZEOF_MCH(mc, new_width), "hash link"); - /* NOTREACHED */ - return NULL; + svalue_t *src, *dest; + p_int i; + + mc2 = new_map_chain(m2); + if (!mc2) + { + xfree(hm2); + outofmem(SIZEOF_MCH(mc, new_width), "hash link"); + /* NOTREACHED */ + return NULL; + } + + /* Copy the key and the common values */ + for (src = &(mc->data[0]), dest = &(mc2->data[0]), i = common_width + ; i >= 0 + ; --i, src++, dest++) + { + assign_svalue_no_free(dest, src); + } + + /* Zero out any extraneous values */ + for (dest = &(mc2->data[common_width+1]), i = new_width - common_width + ; i > 0 + ; --i, dest++) + { + put_number(dest, 0); + } + + + mc2->next = last; + last = mc2; } - - /* Copy the key and the common values */ - for (src = &(mc->data[0]), dest = &(mc2->data[0]), i = common_width - ; i >= 0 - ; --i, src++, dest++) - { - assign_svalue_no_free(dest, src); - } - - /* Zero out any extraneous values */ - for (dest = &(mc2->data[common_width+1]), i = new_width - common_width - ; i > 0 - ; --i, dest++) - { - put_number(dest, 0); - } - - - mc2->next = last; - last = mc2; - } *mcp2++ = last; } while (--size); @@ -1595,7 +1611,24 @@ resize_mapping (mapping_t *m, mp_int new_width) ; src_ix < cm->size ; src_ix++, src_key++) { - if (src_key->type != T_INVALID) + if (src_key->type == T_INVALID) + ; /* Do nothing */ + else if (destructed_object_ref(src_key)) + { + /* We have to fill the space. + * (Alternatively we could decrease m->cond->size.) + */ + p_int i; + + num_entries--; + + dest_key->type = T_INVALID; + dest_key++; + + for (i = new_width; i > 0; i--, dest_data++) + put_number(dest_data, 0); + } + else { p_int i; @@ -1616,7 +1649,7 @@ resize_mapping (mapping_t *m, mp_int new_width) /* --- Finalize the basis structure --- */ - m2->num_entries = m->num_entries; + m2->num_entries = num_entries; /* That's it. */ return m2; @@ -1671,8 +1704,9 @@ add_mapping (mapping_t *m1, mapping_t *m2) return copy_mapping(m1); } - errorf("Mappings to be added are of different width: %ld vs. %ld\n" - , (long)num_values, (long)m2->num_values); + errorf("Mappings to be added are of different width: %"PRIdMPINT + " vs. %"PRIdPINT"\n", + num_values, m2->num_values); } @@ -1730,7 +1764,8 @@ add_mapping (mapping_t *m1, mapping_t *m2) ; cm1_ix < cm1size && cm2_ix < cm2size ; NOOP ) { - int cmp, i; + int cmp; + p_int i; if (src1_key->type == T_INVALID || destructed_object_ref(src1_key) @@ -1793,7 +1828,7 @@ add_mapping (mapping_t *m1, mapping_t *m2) for ( ; cm1_ix < cm1size; cm1_ix++, src1_key++) { svalue_t *data = COND_DATA(cm1, cm1_ix, num_values); - int i; + p_int i; if (src1_key->type != T_INVALID && !destructed_object_ref(src1_key)) @@ -1811,7 +1846,7 @@ add_mapping (mapping_t *m1, mapping_t *m2) for ( ; cm2_ix < cm2size; cm2_ix++, src2_key++) { svalue_t *data = COND_DATA(cm2, cm2_ix, num_values); - int i; + p_int i; if (src2_key->type != T_INVALID && !destructed_object_ref(src2_key)) @@ -1834,7 +1869,7 @@ add_mapping (mapping_t *m1, mapping_t *m2) for ( ; (p_int)num_entries < cm3size; num_entries++) { - int i; + p_int i; dest_key->type = T_INVALID; dest_key++; @@ -1864,7 +1899,7 @@ add_mapping (mapping_t *m1, mapping_t *m2) for (mc = *mcp++; mc; mc = mc->next) { svalue_t * src, * dest; - int i; + p_int i; src = &(mc->data[0]); dest = get_map_lvalue_unchecked(m3, src); @@ -1894,7 +1929,7 @@ add_mapping (mapping_t *m1, mapping_t *m2) for (mc = *mcp++; mc; mc = mc->next) { svalue_t * src, * dest; - int i; + p_int i; src = &(mc->data[0]); dest = get_map_lvalue_unchecked(m3, src); @@ -2060,7 +2095,8 @@ compact_mapping (mapping_t *m, Bool force) cm = m->cond; if (hm && hm->ref) { - fatal("compact_mapping(): remaining protector ref count %ld!\n", hm->ref); + fatal("compact_mapping(): remaining protector ref count %" + PRIdPINT"!\n", hm->ref); } /* Test if the mapping is dirty at all. @@ -2184,7 +2220,7 @@ compact_mapping (mapping_t *m, Bool force) if (last_hash) { - p_int d = svalue_cmp(&(mcp->data[0]), &(last_hash->data[0])); + int d = svalue_cmp(&(mcp->data[0]), &(last_hash->data[0])); if (d < 0) { last_hash->next = hook1; @@ -2260,7 +2296,7 @@ compact_mapping (mapping_t *m, Bool force) { /* Sort the next runlength elements onto out1 */ while (1) { - p_int d = svalue_cmp(&(hook1->data[0]), &(hook2->data[0])); + int d = svalue_cmp(&(hook1->data[0]), &(hook2->data[0])); if (d > 0) { @@ -2352,7 +2388,7 @@ compact_mapping (mapping_t *m, Bool force) map_chain_t *temp; svalue_t *src; - int i; + p_int i; *dest_key++ = hook1->data[0]; @@ -2367,7 +2403,7 @@ compact_mapping (mapping_t *m, Bool force) { /* Take entry from the old condensed part */ - int i; + p_int i; *dest_key++ = *src_key++; @@ -2389,7 +2425,7 @@ compact_mapping (mapping_t *m, Bool force) { if (src_key->type != T_INVALID) { - int i; + p_int i; *dest_key++ = *src_key++; @@ -2412,7 +2448,7 @@ compact_mapping (mapping_t *m, Bool force) { map_chain_t *temp; svalue_t *src; - int i; + p_int i; *dest_key++ = hook1->data[0]; @@ -2553,7 +2589,7 @@ mapping_overhead (mapping_t *m) */ struct set_mapping_user_locals { - int num_values; /* Number of values per key */ + p_int num_values; /* Number of values per key */ object_t *owner; /* Owner to set */ svalue_t **hairy; /* Next free entry in the array of keys which need manual tweaking */ @@ -2575,7 +2611,7 @@ set_mapping_user_filter (svalue_t *key, svalue_t *data, void *extra) */ { - int i; + p_int i; struct set_mapping_user_locals *locals; object_t *owner; @@ -2608,7 +2644,7 @@ set_mapping_user (mapping_t *m, object_t *owner) */ { - int num_values; + p_int num_values; mp_int total; wiz_list_t *user; struct set_mapping_user_locals locals; @@ -2958,12 +2994,12 @@ clean_stale_mappings (void) { #ifdef VERBOSE fprintf(stderr, "%s Unable to compact stale mapping: Out of memory " - "for new condensed block (%ld bytes).\n" - , time_stamp(), (long)size); + "for new condensed block (%zu bytes).\n" + , time_stamp(), size); #endif debug_message("%s Unable to compact stale mapping: Out of memory " - "for new condensed block (%ld bytes).\n" - , time_stamp(), (long)size); + "for new condensed block (%zu bytes).\n" + , time_stamp(), size); /* No use in even trying to compact the much bigger data * block either. @@ -3085,19 +3121,20 @@ f_m_allocate (svalue_t *sp) p_int width = sp[0].u.number; if (size < 0) - errorf("Illegal mapping size: %ld\n", size); + errorf("Illegal mapping size: %"PRIdPINT"\n", size); if (width < 0) - errorf("Illegal mapping width: %ld\n", width); + errorf("Illegal mapping width: %"PRIdPINT"\n", width); if (max_mapping_size && size * (1 + width) > (p_int)max_mapping_size) - errorf("Illegal mapping size: %ld elements (%ld x %ld).\n" - , size * (1+width) - , size, width); + errorf("Illegal mapping size: %"PRIdMPINT + " elements (%"PRIdPINT" x %"PRIdPINT").\n", + (mp_int)size * (1+width), + size, width); if (max_mapping_keys && size > (p_int)max_mapping_keys) - errorf("Illegal mapping size: %ld entries.\n", size); + errorf("Illegal mapping size: %"PRIdPINT" entries.\n", size); sp--; @@ -3107,7 +3144,8 @@ f_m_allocate (svalue_t *sp) /* sp points to a number-typed svalue, so freeing won't * be a problem. */ - errorf("Out of memory for mapping[%ld,%ld].\n", size, width); + errorf("Out of memory for mapping[%"PRIdPINT",%"PRIdPINT"].\n", + size, width); /* NOTREACHED */ } sp->type = T_MAPPING; @@ -3135,7 +3173,7 @@ v_m_add (svalue_t *sp, int num_arg) mapping_t *m; svalue_t *argp; svalue_t *entry; - int num_values; + p_int num_values; argp = sp - num_arg + 1; m = argp->u.map; @@ -3214,7 +3252,7 @@ m_indices (mapping_t *m) mp_int size; check_map_for_destr(m); - size = (mp_int)MAP_SIZE(m); + size = MAP_SIZE(m); v = allocate_array(size); /* might cause error */ svp = v->item; walk_mapping(m, m_indices_filter, &svp); @@ -3267,8 +3305,8 @@ f_m_values (svalue_t *sp) mapping_t *m; vector_t *v; struct mvf_info vip; - mp_int size; - int num; + p_int size; + p_int num; /* Get and check the arguments */ num = sp->u.number; @@ -3277,12 +3315,12 @@ f_m_values (svalue_t *sp) m = sp->u.map; if (num < 0 || num >= m->num_values) - errorf("Illegal index %d to m_values(): should be in 0..%ld.\n" - , num, (long)m->num_values-1); + errorf("Illegal index %"PRIdPINT" to m_values(): should be in 0..%" + PRIdPINT".\n", num, m->num_values-1); /* Get the size of the mapping */ check_map_for_destr(m); - size = (mp_int)MAP_SIZE(m); + size = MAP_SIZE(m); if (size > 0 && m->num_values < 1) errorf("m_values() applied on mapping with no values.\n"); @@ -3311,7 +3349,7 @@ add_to_mapping_filter (svalue_t *key, svalue_t *data, void *extra) { svalue_t *data2; - int i; + p_int i; data2 = get_map_lvalue_unchecked((mapping_t *)extra, key); if (!data2) @@ -3378,8 +3416,9 @@ add_to_mapping (mapping_t *m1, mapping_t *m2) } else { - errorf("Mappings to be added are of different width: %ld vs. %ld\n" - , (long)m1->num_values, (long)m2->num_values); + errorf("Mappings to be added are of different width: %"PRIdPINT + " vs. %"PRIdPINT"\n", + m1->num_values, m2->num_values); return; } } @@ -3452,9 +3491,9 @@ map_intersect_filter (svalue_t *key, svalue_t *data UNUSED, void *extra) src = get_map_value(m, key); if (src != &const0) { - int num_values = m->num_values; + p_int num_values = m->num_values; svalue_t * dest; - int j; + p_int j; dest = get_map_lvalue(rc, key); if (!dest) @@ -3488,9 +3527,9 @@ map_intersect (mapping_t *m, svalue_t * val) if (val->type == T_POINTER) { vector_t * vec = val->u.vec; - size_t vecsize = VEC_SIZE(vec); - int num_values = m->num_values; - size_t i; + p_int vecsize = VEC_SIZE(vec); + p_int num_values = m->num_values; + p_int i; rc = allocate_mapping(vecsize, num_values); if (!rc) @@ -3507,7 +3546,7 @@ map_intersect (mapping_t *m, svalue_t * val) if (src != &const0) { svalue_t * dest; - int j; + p_int j; dest = get_map_lvalue(rc, &vec->item[i]); if (!dest) @@ -3525,7 +3564,7 @@ map_intersect (mapping_t *m, svalue_t * val) else if (val->type == T_MAPPING) { mapping_t * map = val->u.map; - int num_values = m->num_values; + p_int num_values = m->num_values; struct map_intersect_s data; rc = allocate_mapping(MAP_SIZE(map), num_values); @@ -3566,12 +3605,12 @@ map_intersect_array (vector_t *vec, mapping_t *map) { Bool *flags; /* The result from match_arrays() */ - size_t result_size; /* Size of the result array */ + p_int result_size; /* Size of the result array */ vector_t *result; /* Result array */ svalue_t *dest; /* Pointer for storing the result elements */ - size_t i; + p_int i; - size_t vec_size = VEC_SIZE(vec); + p_int vec_size = VEC_SIZE(vec); /* Handle empty arrays */ @@ -3615,7 +3654,7 @@ map_intersect_array (vector_t *vec, mapping_t *map) xfree(flags); free_mapping(map); free_array(vec); - errorf("Illegal array size: %lu.\n", (unsigned long)result_size); + errorf("Illegal array size: %"PRIdPINT".\n", result_size); } result = allocate_array(result_size); @@ -3810,7 +3849,7 @@ v_walk_mapping (svalue_t *sp, int num_arg) callback_t cb; int error_index; mapping_t *m; /* Mapping to walk */ - int num_values; /* Number of values per entry */ + p_int num_values; /* Number of values per entry */ svalue_t *read_pointer; /* Prepared mapping values */ mp_int i; @@ -3848,7 +3887,7 @@ v_walk_mapping (svalue_t *sp, int num_arg) */ while (--i >= 0) { - int j; + p_int j; svalue_t *sp2, *data; if (!callback_object(&cb)) @@ -3916,12 +3955,12 @@ x_filter_mapping (svalue_t *sp, int num_arg, Bool bFull) mapping_t *m; /* Mapping to filter */ int error_index; callback_t cb; - int num_values; /* Width of the mapping */ + p_int num_values; /* Width of the mapping */ vector_t *dvec; /* Values of one key */ svalue_t *dvec_sp; /* Stackentry of dvec */ svalue_t *read_pointer; /* Prepared mapping values */ svalue_t *v; - int i, j; + p_int i, j; /* Locate the arguments on the stack and extract them */ arg = sp - num_arg + 1; @@ -4144,11 +4183,11 @@ x_map_mapping (svalue_t *sp, int num_arg, Bool bFull) svalue_t *arg; /* Begin of arguments on the stack */ mapping_t *arg_m; /* Mapping to map */ mapping_t *m; /* Result mapping */ - int num_values; /* Width of the mapping */ + p_int num_values; /* Width of the mapping */ vector_t *vec; /* Indices of m */ svalue_t *dvec_sp; /* Stackentry of dvec */ vector_t *dvec; /* Values of one key */ - long i; + p_int i; svalue_t *key; callback_t cb; int error_index; @@ -4204,7 +4243,7 @@ x_map_mapping (svalue_t *sp, int num_arg, Bool bFull) dvec_sp = sp; } - m = allocate_mapping((i = (long)VEC_SIZE(vec)), 1); + m = allocate_mapping((i = VEC_SIZE(vec)), 1); if (!m) { inter_sp = sp; @@ -4255,7 +4294,7 @@ x_map_mapping (svalue_t *sp, int num_arg, Bool bFull) } else { - int j; + p_int j; svalue_t *svp; v = get_map_value(arg_m, key); @@ -4334,7 +4373,7 @@ v_m_contains (svalue_t *sp, int num_arg) * int m_contains(mixed &data1, ..., &dataN, map, key) * * If the mapping contains the key map, the corresponding values - * are assigned to the data arguments, which massed be passed by + * are assigned to the data arguments, which must be passed by * reference, and 1 is returned. If key is not in map, 0 is * returned and the data args are left unchanged. * It is possible to use this function for a 0-value mapping, in @@ -4352,8 +4391,8 @@ v_m_contains (svalue_t *sp, int num_arg) if (sp[-1].type != T_MAPPING) vefun_arg_error(num_arg-1, T_MAPPING, sp[-1].type, sp); if (sp[-1].u.map->num_values != num_arg - 2) - errorf("Not enough lvalues: given %ld, required %ld.\n" - , (long)num_arg-2, (long)sp[-1].u.map->num_values); + errorf("Not enough lvalues: given %d, required %"PRIdPINT".\n", + num_arg-2, sp[-1].u.map->num_values); item = get_map_value(sp[-1].u.map, sp); if (item == &const0) @@ -4411,8 +4450,8 @@ f_m_entry (svalue_t *sp) data = get_map_value(sp[-1].u.map, sp); if (&const0 != data) { - int num_values = sp[-1].u.map->num_values; - int i; + p_int num_values = sp[-1].u.map->num_values; + p_int i; rc = allocate_array(num_values); @@ -4450,7 +4489,7 @@ f_m_reallocate (svalue_t *sp) */ { - int new_width; /* Requested width of the target mapping */ + p_int new_width; /* Requested width of the target mapping */ mapping_t *m; /* Argument mapping */ mapping_t *new_m; /* New mapping */ @@ -4458,7 +4497,7 @@ f_m_reallocate (svalue_t *sp) new_width = sp->u.number; if (new_width < 0) { - errorf("Illegal width to m_reallocate(): %ld\n", (long)new_width); + errorf("Illegal width to m_reallocate(): %"PRIdPINT"\n", new_width); /* NOTREACHED */ return sp; } @@ -4549,26 +4588,28 @@ v_mkmapping (svalue_t *sp, int num_arg) if (sp[-num_arg+1].type == T_POINTER) { - long i, length, num_values; + int i, num_values; /* contains num_arg, which is int */ + p_int length; /* VEC_SIZE, array sizes */ svalue_t *key; /* Check the arguments and set length to the size of * the shortest array. */ - length = LONG_MAX; + length = PINT_MAX; for (i = -num_arg; ++i <= 0; ) { if ( sp[i].type != T_POINTER ) vefun_arg_error(i+num_arg, T_POINTER, sp[i].type, sp); - if (length > (long)VEC_SIZE(sp[i].u.vec)) - length = (long)VEC_SIZE(sp[i].u.vec); + if (length > VEC_SIZE(sp[i].u.vec)) + length = VEC_SIZE(sp[i].u.vec); } - if (max_mapping_size && length * num_arg > (p_int)max_mapping_size) - errorf("Illegal mapping size: %ld elements (%ld x %ld)\n" - , length * num_arg, length, (long)num_arg); + if (max_mapping_size && (mp_int)length * num_arg > (mp_int)max_mapping_size) + errorf("Illegal mapping size: %"PRIdMPINT + " elements (%"PRIdPINT" x %d)\n" + , (mp_int)length * num_arg, length, num_arg); if (max_mapping_keys && length > (p_int)max_mapping_keys) - errorf("Illegal mapping size: %ld entries\n", length); + errorf("Illegal mapping size: %"PRIdPINT" entries\n", length); /* Allocate the mapping */ num_values = num_arg - 1; @@ -4635,14 +4676,14 @@ f_unmkmapping (svalue_t *sp) vector_t *v; struct mvf_info vip; mp_int size; - int i; + p_int i; /* Get the arguments */ m = sp->u.map; /* Determine the size of the mapping and allocate the result vector */ check_map_for_destr(m); - size = (mp_int)MAP_SIZE(m); + size = MAP_SIZE(m); v = allocate_array(m->num_values+1); /* Allocate the sub vectors */ @@ -4680,7 +4721,7 @@ f_widthof (svalue_t *sp) */ { - int width; + p_int width; if (sp->type == T_NUMBER && sp->u.number == 0) return sp; diff --git a/src/mempools.c b/src/mempools.c index 82592fe..3a0854a 100644 --- a/src/mempools.c +++ b/src/mempools.c @@ -266,12 +266,12 @@ mb_status (strbuf_t * sbuf, Bool verbose) { strbuf_add(sbuf, "\nMemory Buffers:\n"); strbuf_add(sbuf, "---------------\n"); - strbuf_addf(sbuf, "File data: %8lu\n", membuffers[mbFile].size); - strbuf_addf(sbuf, "Swap buffer: %8lu\n", membuffers[mbSwap].size); + strbuf_addf(sbuf, "File data: %8zu\n", membuffers[mbFile].size); + strbuf_addf(sbuf, "Swap buffer: %8zu\n", membuffers[mbSwap].size); } else { - strbuf_addf(sbuf, "Memory buffers:\t\t\t\t %9lu\n", res); + strbuf_addf(sbuf, "Memory buffers:\t\t\t\t %9zu\n", res); } return res; diff --git a/src/mregex.c b/src/mregex.c index 5a4d9ee..a29b536 100644 --- a/src/mregex.c +++ b/src/mregex.c @@ -421,6 +421,22 @@ rx_compile_pcre (string_t * expr, int opt, Bool from_ed, regdata_t * rdata) errorf("pcre: %s\n", pErrmsg); return 0; } + /* We have to ensure to have an initialized pHints structure for + setting the recursion limit later on */ + if (pHints == NULL) + { + pcre_malloc_err = "allocating memory for pHints section in regexp"; + pHints = (pcre_extra *)pcre_xalloc(sizeof(pcre_extra)); + if (pHints == NULL) + { + if (from_ed) + add_message("pcre: Could not allocate memory for pHints\n"); + else + errorf("pcre: Could not allocate memory for pHints\n"); + return 0; + } + pHints->flags = 0; + } { int rc; @@ -685,18 +701,28 @@ rx_exec (regexp_t *pRegexp, string_t * string, size_t start) if (prog->opt & RE_NOTEMPTY) pcre_opt |= PCRE_NOTEMPTY; pHints = prog->pHints; - if (pHints && max_eval_cost) - { - pHints->flags |= PCRE_EXTRA_MATCH_LIMIT; - if (max_eval_cost > eval_cost + 1) - pHints->match_limit = max_eval_cost - eval_cost - 1; - else - pHints->match_limit = 1; - } - else if (pHints) - { - pHints->flags &= ~PCRE_EXTRA_MATCH_LIMIT; - } + /* If LD_PCRE_RECURSION_LIMIT is defined we set a limit for match. If + * PCRE_EXTRA_MATCH_LIMIT_RECURSION is defined, we have a new libpcre, + * which supports limiting the recursions. Otherwise we have to limit + * the no of calls to match(). + * TODO: Instead of the conditional compilation we should update the + * TODO::built-in pcre package. + */ +#ifdef LD_PCRE_RECURSION_LIMIT +#ifdef PCRE_EXTRA_MATCH_LIMIT_RECURSION + pHints->flags |= PCRE_EXTRA_MATCH_LIMIT_RECURSION; + pHints->match_limit_recursion = LD_PCRE_RECURSION_LIMIT; +#else + pHints->flags |= PCRE_EXTRA_MATCH_LIMIT; + pHints->match_limit = LD_PCRE_RECURSION_LIMIT; +#endif /* PCRE_EXTRA_MATCH_LIMIT_RECURSION */ +#else /* LD_PCRE_RECURSION_LIMIT */ +#ifdef PCRE_EXTRA_MATCH_LIMIT_RECURSION + pHints->flags &= ~PCRE_EXTRA_MATCH_LIMIT_RECURSION +#else + pHints->flags &= ~PCRE_EXTRA_MATCH_LIMIT; +#endif /* PCRE_EXTRA_MATCH_LIMIT_RECURSION */ +#endif /* LD_PCRE_RECURSION_LIMIT */ rc = pcre_exec( prog->pProg, pHints , get_txt(string), mstrsize(string), start, pcre_opt @@ -748,18 +774,28 @@ rx_exec_str (regexp_t *pRegexp, char * string, char * start) if (prog->opt & RE_NOTEMPTY) pcre_opt |= PCRE_NOTEMPTY; pHints = prog->pHints; - if (pHints && max_eval_cost) - { - pHints->flags |= PCRE_EXTRA_MATCH_LIMIT; - if (max_eval_cost > eval_cost + 1) - pHints->match_limit = max_eval_cost - eval_cost - 1; - else - pHints->match_limit = 1; - } - else if (pHints) - { - pHints->flags &= ~PCRE_EXTRA_MATCH_LIMIT; - } + /* If LD_PCRE_RECURSION_LIMIT is defined we set a limit for match. If + * PCRE_EXTRA_MATCH_LIMIT_RECURSION is defined, we have a new libpcre, + * which supports limiting the recursions. Otherwise we have to limit + * the no of calls to match(). + * TODO: Instead of the conditional compilation we should update the + * TODO::built-in pcre package. + */ +#ifdef LD_PCRE_RECURSION_LIMIT +#ifdef PCRE_EXTRA_MATCH_LIMIT_RECURSION + pHints->flags |= PCRE_EXTRA_MATCH_LIMIT_RECURSION; + pHints->match_limit_recursion = LD_PCRE_RECURSION_LIMIT; +#else + pHints->flags |= PCRE_EXTRA_MATCH_LIMIT; + pHints->match_limit = LD_PCRE_RECURSION_LIMIT; +#endif /* PCRE_EXTRA_MATCH_LIMIT_RECURSION */ +#else /* LD_PCRE_RECURSION_LIMIT */ +#ifdef PCRE_EXTRA_MATCH_LIMIT_RECURSION + pHints->flags &= ~PCRE_EXTRA_MATCH_LIMIT_RECURSION +#else + pHints->flags &= ~PCRE_EXTRA_MATCH_LIMIT; +#endif /* PCRE_EXTRA_MATCH_LIMIT_RECURSION */ +#endif /* LD_PCRE_RECURSION_LIMIT */ rc = pcre_exec( prog->pProg, pHints , start, strlen(start), string - start, pcre_opt @@ -1172,12 +1208,13 @@ rxcache_status (strbuf_t *sbuf, Bool verbose) { strbuf_add(sbuf, "\nRegexp cache status:\n"); strbuf_add(sbuf, "--------------------\n"); - strbuf_addf(sbuf, "Expressions in cache: %lu (%.1f%%)\n" + strbuf_addf(sbuf, "Expressions in cache: %"PRIu32" (%.1f%%)\n" , iNumXEntries, 100.0 * (float)iNumXEntries / RXCACHE_TABLE); - strbuf_addf(sbuf, "Memory allocated: %lu\n", iXSizeAlloc); + strbuf_addf(sbuf, "Memory allocated: %"PRIu32"\n", iXSizeAlloc); iNumXReq = iNumXRequests ? iNumXRequests : 1; strbuf_addf(sbuf - , "Requests: %lu - Found: %lu (%.1f%%) - Coll: %lu (%.1f%% req/%.1f%% entries)\n" + , "Requests: %"PRIu32" - Found: %"PRIu32" (%.1f%%) - " + "Coll: %"PRIu32" (%.1f%% req/%.1f%% entries)\n" , iNumXRequests, iNumXFound, 100.0 * (float)iNumXFound/(float)iNumXReq , iNumXCollisions, 100.0 * (float)iNumXCollisions/(float)iNumXReq , 100.0 * (float)iNumXCollisions/(iNumXEntries ? iNumXEntries : 1) @@ -1185,7 +1222,8 @@ rxcache_status (strbuf_t *sbuf, Bool verbose) } else { - strbuf_addf(sbuf, "Regexp cache:\t\t\t%8ld %9lu\n", iNumXEntries, iXSizeAlloc); + strbuf_addf(sbuf, "Regexp cache:\t\t\t%8"PRId32" %9"PRIu32"\n", + iNumXEntries, iXSizeAlloc); } return iXSizeAlloc; diff --git a/src/mstrings.c b/src/mstrings.c index 2bf4e25..e27869d 100644 --- a/src/mstrings.c +++ b/src/mstrings.c @@ -111,7 +111,7 @@ static string_t ** stringtable = NULL; * This does include the memory by the string management structures. */ -static mp_uint mstr_tabled = 0; +static mp_uint mstr_tabled_count = 0; /* Number of distinct strings in the string table. */ @@ -128,14 +128,14 @@ static mp_uint mstr_added = 0; */ static mp_uint mstr_deleted = 0; - /* Number of distinct strings delete from the string table. + /* Number of distinct strings deleted from the string table. */ static mp_uint mstr_collisions = 0; /* Number of collisions when adding a new distinct string. */ -static mp_uint mstr_untabled = 0; +static mp_uint mstr_untabled_count = 0; /* Number of distinct untabled strings. */ @@ -180,7 +180,7 @@ unsigned long stNumTabledCheckedSearch = 0; /*-------------------------------------------------------------------------*/ static INLINE whash_t -hash_string (const char * const s, size_t size) +hash_string_inl (const char * const s, size_t size) /* Compute the hash for string of length and return it. * The result will always be non-zero. @@ -193,7 +193,13 @@ hash_string (const char * const s, size_t size) if (!hash) hash = 1 << (sizeof (hash) * CHAR_BIT - 1); return hash; -} /* hash_string() */ +} /* hash_string_inl() */ + +whash_t +hash_string (const char * const s, size_t size) +{ + return hash_string_inl(s, size); +} /*-------------------------------------------------------------------------*/ static INLINE whash_t @@ -204,7 +210,7 @@ get_hash (string_t * pStr) { if (!pStr->hash) - pStr->hash = hash_string(pStr->txt, pStr->size); + pStr->hash = hash_string_inl(pStr->txt, pStr->size); return pStr->hash; } /* get_hash() */ @@ -363,7 +369,7 @@ make_new_tabled (const char * const pTxt, size_t size, whash_t hash MTRACE_DECL) msize = mstr_mem_size(string); mstr_used++; mstr_used_size += msize; - mstr_tabled++; + mstr_tabled_count++; mstr_tabled_size += msize; } @@ -409,7 +415,7 @@ mstring_alloc_string (size_t iSize MTRACE_DECL) msize = mstr_mem_size(string); mstr_used++; mstr_used_size += msize; - mstr_untabled++; + mstr_untabled_count++; mstr_untabled_size += msize; } @@ -486,7 +492,7 @@ mstring_new_tabled (const char * const pTxt MTRACE_DECL) string_t * string; size = strlen(pTxt); - hash = hash_string(pTxt, size); + hash = hash_string_inl(pTxt, size); /* Check if the string has already been tabled */ string = find_and_move(pTxt, size, hash); @@ -516,7 +522,7 @@ mstring_new_n_tabled (const char * const pTxt, size_t size MTRACE_DECL) whash_t hash; string_t * string; - hash = hash_string(pTxt, size); + hash = hash_string_inl(pTxt, size); /* Check if the string has already been tabled */ string = find_and_move(pTxt, size, hash); @@ -581,10 +587,10 @@ table_string (string_t * pStr MTRACE_DECL) pStr->next = stringtable[idx]; stringtable[idx] = pStr; - mstr_tabled++; + mstr_tabled_count++; mstr_tabled_size += msize; - mstr_untabled--; + mstr_untabled_count--; mstr_untabled_size -= msize; string = pStr; @@ -792,7 +798,7 @@ mstring_find_tabled_str (const char * const pTxt, size_t size) { whash_t hash; - hash = hash_string(pTxt, size); + hash = hash_string_inl(pTxt, size); return find_and_move(pTxt, size, hash); } /* mstring_find_tabled_str() */ @@ -831,7 +837,7 @@ mstring_free (string_t *s) int idx; - mstr_tabled--; + mstr_tabled_count--; mstr_tabled_size -= msize; idx = HashToIndex(get_hash(s)); @@ -853,7 +859,7 @@ mstring_free (string_t *s) { /* An untabled string */ - mstr_untabled--; + mstr_untabled_count--; mstr_untabled_size -= msize; } @@ -861,36 +867,6 @@ mstring_free (string_t *s) xfree(s); } /* mstring_free() */ -/*-------------------------------------------------------------------------*/ -string_t * -mstring_ref ( string_t * str) - -/* Aliased to: ref_mstring_safe(s) - * - * Increment the refcount for string and return the ref'ed string. - * In contrast to macro ref_mstring(), this function can handle arguments - * with sideeffects. - */ - -{ - return ref_mstring(str); -} /* mstring_ref() */ - -/*-------------------------------------------------------------------------*/ -unsigned long -mstring_deref ( string_t * str) - -/* Aliased to: deref_mstring_safe(s) - * - * Decrement the refcount for string and return the new refcount. - * In contrast to macro deref_mstring(), this function can handle arguments - * with sideeffects. - */ - -{ - return deref_mstring(str); -} /* mstring_deref() */ - /*-------------------------------------------------------------------------*/ Bool mstring_equal(string_t * const pStr1, string_t * const pStr2) @@ -1048,12 +1024,13 @@ mstring_mstr_n_str ( const string_t * const pStr, size_t start size_t left; char first; - if (start >= mstrsize(pStr)) + if (start > mstrsize(pStr)) return NULL; /* Initialize 'characters remaining' and 'current position' */ left = mstrsize(pStr) - start; - cp = get_txt(pStr)+start; + /* remove the const qualifier temporarily when calling get_txt(). */ + cp = get_txt((string_t *const)pStr)+start; /* Special case: strstr("text", "") */ if (len == 0) @@ -1099,12 +1076,12 @@ mstring_mstr_rn_str ( const string_t * const pStr, size_t start size_t left; char first; - if (start >= mstrsize(pStr)) + if (start > mstrsize(pStr)) return NULL; /* Initialize 'characters remaining' and 'current position' */ left = mstrsize(pStr) - start; - cp = get_txt(pStr)+start; + cp = get_txt((string_t *const)pStr)+start; /* Special case: strrstr("text", "") */ if (len == 0) @@ -1119,7 +1096,7 @@ mstring_mstr_rn_str ( const string_t * const pStr, size_t start && 0 == memcmp(cp, pTxt, len) ) return cp; - } while (cp != get_txt(pStr)); + } while (cp != get_txt((string_t *const)pStr)); return NULL; } /* mstring_mstr_n_str() */ @@ -1146,7 +1123,7 @@ mstring_add_slash (const string_t *str MTRACE_DECL) { txt = get_txt(tmp); *txt = '/'; - memcpy(txt+1, get_txt(str), mstrsize(str)); + memcpy(txt+1, get_txt((string_t *const)str), mstrsize(str)); } return tmp; } /* mstring_add_slash() */ @@ -1234,7 +1211,7 @@ mstring_cvt_progname (const string_t *str MTRACE_DECL) const char * txt, *p; char *txt2; - txt = get_txt(str); + txt = get_txt((string_t *const)str); len = mstrsize(str); p = strrchr(txt, '.'); @@ -1287,8 +1264,8 @@ mstring_add (const string_t *left, const string_t *right MTRACE_DECL) char * txt; txt = get_txt(tmp); - memcpy(txt, get_txt(left), lleft); - memcpy(txt+lleft, get_txt(right), lright); + memcpy(txt, get_txt((string_t *const)left), lleft); + memcpy(txt+lleft, get_txt((string_t *const)right), lright); } return tmp; } /* mstring_add() */ @@ -1317,7 +1294,7 @@ mstring_add_txt (const string_t *left, const char *right, size_t len MTRACE_DECL if (tmp) { txt = get_txt(tmp); - memcpy(txt, get_txt(left), lleft); + memcpy(txt, get_txt((string_t *const)left), lleft); memcpy(txt+lleft, right, len); } return tmp; @@ -1348,7 +1325,7 @@ mstring_add_to_txt (const char *left, size_t len, const string_t *right MTRACE_D { txt = get_txt(tmp); memcpy(txt, left, len); - memcpy(txt+len, get_txt(right), lright); + memcpy(txt+len, get_txt((string_t *const)right), lright); } return tmp; } /* mstring_add_to_txt() */ @@ -1432,7 +1409,7 @@ mstring_repeat (const string_t *base, size_t num MTRACE_DECL) char * txt = get_txt(result); /* Seed result[] with one copy of the string */ - memcpy(txt, get_txt(base), len); + memcpy(txt, get_txt((string_t *const)base), len); /* Repeatedly double the string in result */ curlen = len; @@ -1506,7 +1483,7 @@ mstring_extract (const string_t *str, size_t start, long end MTRACE_DECL) result = mstring_alloc_string(reslen MTRACE_PASS); if (result && reslen) { - memcpy(get_txt(result), get_txt(str)+start, reslen); + memcpy(get_txt(result), get_txt((string_t *const)str)+start, reslen); } return result; } /* mstring_extract() */ @@ -1524,8 +1501,8 @@ mstring_prefixed (const string_t *p, const string_t *s) const char *pp, *ps; size_t lp, ls; - lp = mstrsize(p); pp = get_txt(p); - ls = mstrsize(s); ps = get_txt(s); + lp = mstrsize(p); pp = get_txt((string_t *const)p); + ls = mstrsize(s); ps = get_txt((string_t *const)s); for (; lp > 0 && ls > 0; lp--, ls--) { @@ -1549,9 +1526,9 @@ mstring_chr (const string_t *p, char c) { char *pp; - pp = memchr(get_txt(p), c, mstrsize(p)); + pp = memchr(get_txt((string_t *const)p), c, mstrsize(p)); if (pp != NULL) - return pp - get_txt(p); + return pp - get_txt((string_t *const)p); return -1; } /* mstring_chr() */ @@ -1676,9 +1653,9 @@ mstring_gc_table (void) next = this->next; } - mstr_untabled++; + mstr_untabled_count++; mstr_untabled_size += mstr_mem_size(this); - mstr_tabled--; + mstr_tabled_count--; mstr_tabled_size += mstr_mem_size(this); mstr_deleted++; @@ -1715,10 +1692,10 @@ add_string_status (strbuf_t *sbuf, Bool verbose) mp_uint distinct_overhead; stringtable_size = HTABLE_SIZE * sizeof(string_t *); - distinct_strings = mstr_tabled + mstr_untabled; + distinct_strings = mstr_tabled_count + mstr_untabled_count; distinct_size = mstr_tabled_size + mstr_untabled_size; - distinct_overhead = mstr_tabled * STR_OVERHEAD - + mstr_untabled * STR_OVERHEAD; + distinct_overhead = mstr_tabled_count * STR_OVERHEAD + + mstr_untabled_count * STR_OVERHEAD; if (!verbose) { @@ -1748,20 +1725,20 @@ add_string_status (strbuf_t *sbuf, Bool verbose) , distinct_overhead + stringtable_size ); strbuf_addf(sbuf, " - tabled\t%9lu %9lu (%9lu+%9lu)\n" - , mstr_tabled + , mstr_tabled_count , mstr_tabled_size + stringtable_size , mstr_tabled_size - ? mstr_tabled_size - mstr_tabled * STR_OVERHEAD + ? mstr_tabled_size - mstr_tabled_count * STR_OVERHEAD : 0 - , mstr_tabled * STR_OVERHEAD + stringtable_size + , mstr_tabled_count * STR_OVERHEAD + stringtable_size ); strbuf_addf(sbuf, " - untabled\t%9lu %9lu (%9lu+%9lu)\n" - , mstr_untabled + , mstr_untabled_count , mstr_untabled_size , mstr_untabled_size - ? mstr_untabled_size - mstr_untabled * STR_OVERHEAD + ? mstr_untabled_size - mstr_untabled_count * STR_OVERHEAD : 0 - , mstr_untabled * STR_OVERHEAD + , mstr_untabled_count * STR_OVERHEAD ); strbuf_addf(sbuf, "\nSpace required vs. 'regular C' string implementation: " "%lu%% with, %lu%% without overhead.\n" @@ -1782,7 +1759,7 @@ add_string_status (strbuf_t *sbuf, Bool verbose) , (float)mstr_searchlen_byvalue / (float)mstr_searches_byvalue ); strbuf_addf(sbuf, "Hash chains used: %lu of %lu (%.1f%%)\n" - , mstr_chains, HTABLE_SIZE + , mstr_chains, (unsigned long)HTABLE_SIZE , 100.0 * (float)mstr_chains / (float)HTABLE_SIZE ); strbuf_addf(sbuf, "Distinct strings added: %lu " @@ -1847,9 +1824,9 @@ string_dinfo_status (svalue_t *svp, int value) ST_NUMBER(DID_ST_STR_DELETED, mstr_deleted); ST_NUMBER(DID_ST_STR_COLLISIONS, mstr_collisions); - ST_NUMBER(DID_ST_UNTABLED, mstr_untabled); + ST_NUMBER(DID_ST_UNTABLED, mstr_untabled_count); ST_NUMBER(DID_ST_UNTABLED_SIZE, mstr_untabled_size); - ST_NUMBER(DID_ST_TABLED, mstr_tabled); + ST_NUMBER(DID_ST_TABLED, mstr_tabled_count); ST_NUMBER(DID_ST_TABLED_SIZE, mstr_tabled_size); ST_NUMBER(DID_ST_STR_SEARCHES, mstr_searches); diff --git a/src/mstrings.h b/src/mstrings.h index 5d1fdd9..c4da1e1 100644 --- a/src/mstrings.h +++ b/src/mstrings.h @@ -65,6 +65,7 @@ extern mp_uint mstr_used_size; /* --- Prototypes --- */ extern void mstring_init (void); +extern whash_t hash_string (const char * const s, size_t size); extern whash_t mstring_get_hash (string_t * pStr); extern string_t * mstring_alloc_string (size_t iSize MTRACE_DECL); extern string_t * mstring_new_string (const char * const pTxt MTRACE_DECL); @@ -84,8 +85,6 @@ extern int mstring_compare( string_t * const pStr1 extern Bool mstring_equal( string_t * const pStr1 , string_t * const pStr2); extern void mstring_free (string_t *s); -extern string_t * mstring_ref ( string_t * str); -extern unsigned long mstring_deref ( string_t * str); extern const char * mstring_mstr_n_str(const string_t * const pStr, size_t start, const char * const pTxt, size_t len); extern const char * mstring_mstr_rn_str(const string_t * const pStr, size_t start, const char * const pTxt, size_t len); extern string_t * mstring_add_slash (const string_t *str MTRACE_DECL); @@ -116,110 +115,140 @@ extern void string_dinfo_status(svalue_t *svp, int value); /* --- Inline functions and macros --- */ - -#define mstr_mem_size(s) \ - (sizeof(string_t) + (s)->size) - - /* size_t mstr_mem_size(string_t * s) - * The amount of memory used to hold all this strings' data. +static INLINE size_t mstr_mem_size(const string_t * const s) + __attribute__((nonnull(1))) + __attribute__((pure)); +static INLINE size_t mstr_mem_size(const string_t * const s) + /* The amount of memory used to hold all this strings' data. * Used only to keep the statistics up to date. */ +{ + return sizeof(string_t) + s->size; +} -#define mstr_hash(s) \ - ( (s)->hash ) - - /* whash_t mstr_hash(string_t * s) - * Return the hash value of string , which is 0 if the +static INLINE whash_t mstr_hash(const string_t * const s) + __attribute__((nonnull(1))) + __attribute__((pure)); +static INLINE whash_t mstr_hash(const string_t * const s) + /* Return the hash value of string , which is 0 if the * hash hasn't been computed yet. */ +{ + return s->hash; +} -#define mstr_singular(s) \ - (! ((s)->info.tabled || (s)->info.ref != 1) ) - /* Bool mstr_singular(string_t *s) - * Return FALSE if string has multiple users, ie. is tabled - * or has more than one reference. +static INLINE Bool mstr_singular(const string_t * const s) + __attribute__((nonnull(1))) + __attribute__((pure)); +static INLINE Bool mstr_singular(const string_t * const s) + /* Return FALSE if string has multiple users, ie. is tabled + * or has more than one reference. */ +{ + return ! (s->info.tabled || s->info.ref != 1); +} -#define mstr_untabled(s) \ - (!(s)->info.tabled) - - /* Bool mstr_untabled (string_t *s) - * Return TRUE if string is not tabled. - * The argument must not have sideeffects! +static INLINE Bool mstr_untabled(const string_t * const s) + __attribute__((nonnull(1))) + __attribute__((pure)); +static INLINE Bool mstr_untabled(const string_t * const s) + /* Return TRUE if string is not tabled. */ +{ + return !(s->info.tabled); +} -#define mstr_tabled(s) \ - ((s)->info.tabled) - - /* Bool mstr_tabled (string_t *s) - * Return TRUE if string is tabled - directly or indirectly. - * The argument must not have sideeffects! +static INLINE Bool mstr_tabled(const string_t * const s) + __attribute__((nonnull(1))) + __attribute__((pure)); +static INLINE Bool mstr_tabled(const string_t * const s) + /* Return TRUE if string is tabled - directly or indirectly. */ +{ + return s->info.tabled; +} -#define mstrsize(s) \ - ((s)->size) - - /* size_t mstrsize(string_t *s) - * Return the size (length) of the string . +static INLINE size_t mstrsize(const string_t * const s) + __attribute__((nonnull(1))) + __attribute__((pure)); +static INLINE size_t mstrsize(const string_t * const s) + /* Return the size (length) of the string . */ +{ + return s->size; +} -#define ref_mstring(s) \ - (mstr_used++, mstr_used_size += mstr_mem_size(s), (s)->info.ref ? ++((s)->info.ref) : 0, (s)) - -#define ref_mstring_safe(s) mstring_ref(s) - - /* string_t * ref_mstring (string_t *s) - * string_t * ref_mstring_safe (string_t *s) - * Increment the refcount for string and return the ref'ed string. - * The argument to ref_mstring() must not have sideeffects! +static INLINE string_t *ref_mstring(string_t *const s) __attribute__((nonnull(1))); +static INLINE string_t *ref_mstring(string_t *const s) + /* Increment the refcount for string and return the ref'ed string. */ +{ + mstr_used++; + mstr_used_size += mstr_mem_size(s); + if (s->info.ref) + ++(s->info.ref); + return s; +} -#define deref_mstring(s) \ - (mstr_used--, mstr_used_size -= mstr_mem_size(s), (s)->info.ref ? --((s)->info.ref) : (s)->info.ref) - -#define deref_mstring_safe(s) mstring_deref(s) - - /* int deref_mstring (string_t *s) - * int deref_mstring_safe (string_t *s) - * Decrement the refcount for string and return the new count. - * The argument to deref_mstring() must not have sideeffects! +static INLINE unsigned int deref_mstring(string_t *const s) __attribute__((nonnull(1))); +static INLINE unsigned int deref_mstring(string_t *const s) + /* Decrement the refcount for string and return the new count. */ +{ + mstr_used--; + mstr_used_size -= mstr_mem_size(s); + if (s->info.ref) + --(s->info.ref); + return s->info.ref; +} -#define free_mstring(s) \ - MACRO(string_t * fmsttmp = s; if (fmsttmp != NULL) { if (fmsttmp->info.ref == 1) { mstring_free(fmsttmp); } else deref_mstring(fmsttmp); } ) - - /* void free_mstring(s) - * - * Decrement the refcount for string , and if it reaches 0, - * deallocate altogether. +static INLINE void free_mstring(string_t *const s) __attribute__((nonnull(1))); +static INLINE void free_mstring(string_t *const s) + /* Decrement the refcount for string , and if it reaches 0, + * deallocate altogether. + * TODO: check if s can really be NULL or should be allowed to be. */ +{ + if (s != NULL) + { + if (s->info.ref == 1) + { + mstring_free(s); + } + else + deref_mstring(s); + } +} -#define get_txt(s) \ - ((s)->txt) - - /* char * get_txt (string_t *s) - * - * Return a pointer to the actual string text of string . - * There is at least one '\0' terminating the string text. +static INLINE char *get_txt(string_t *const s) + __attribute__((nonnull(1))) + __attribute__((pure)); +static INLINE char *get_txt(string_t *const s) + /* Return a pointer to the actual string text of string . + * There is at least one '\0' terminating the string text. + * BTW: It is a pity that it can't be const char *get_txt(). */ +{ + return s->txt; +} -#define extract_cstr(d,s,l) \ - MACRO(strncpy((d), get_txt(s), (l)-1); \ - if ((l) > mstrsize(s)) \ - d[mstrsize(s)] = '\0'; \ - else \ - d[(l)-1] = '\0'; \ - ) - - /* void extract_cstr (char * d, string_t *s, size_t l) - * - * Extract the C string from (that is: all characters up to the - * first '\0' resp the end of the string) and copy it into buffer - * of size . The macro makes sure that the string is terminated - * with a '\0' +static INLINE void extract_cstr(char *d, const string_t *const s, size_t l) + __attribute__((nonnull(1,2))); +static INLINE void extract_cstr(char *d, const string_t *const s, size_t l) + /* Extract the C string from (that is: all characters up to the + * first '\0' resp the end of the string) and copy it into buffer + * of size . The macro makes sure that the string is terminated + * with a '\0' */ +{ + strncpy(d, get_txt((string_t*)s), l-1); + if (l > mstrsize(s)) + d[mstrsize(s)] = '\0'; + else + d[l-1] = '\0'; +} /* A handful of shorthands for commonly used functions */ diff --git a/src/my-rusage.h b/src/my-rusage.h index 8797e11..d288235 100644 --- a/src/my-rusage.h +++ b/src/my-rusage.h @@ -39,7 +39,7 @@ extern int getpagesize(); # endif # if defined(sun) || defined(ultrix) - extern int getrusage(int, struct rusage *); + extern int getrusage (int, struct rusage *); # endif #else /* !HAVE_GETRUSAGE */ diff --git a/src/object.c b/src/object.c index 025bd44..3ec51b9 100644 --- a/src/object.c +++ b/src/object.c @@ -271,11 +271,12 @@ dealloc_object ( object_t *ob, const char * file, int line) /* Check the reference count */ if (ob->ref > 0) - fatal("Object with %ld refs passed to _free_object()\n", ob->ref); + fatal("Object with %"PRIdPINT" refs passed to _free_object()\n", + ob->ref); #if 0 && defined(CHECK_OBJECT_REF) if (strchr(get_txt(ob->name), '#') == NULL) - printf("DEBUG: (%s:%d) free_object(%p '%s') ref %ld flags %x\n" + printf("DEBUG: (%s:%d) free_object(%p '%s') ref %"PRIdPINT" flags %x\n" , file, line, ob, get_txt(ob->name), ob->ref, ob->flags); #elif defined(CHECK_OBJECT_REF) # ifdef __MWERKS__ @@ -291,14 +292,14 @@ dealloc_object ( object_t *ob, const char * file, int line) /* Freeing a non-destructed object should never happen */ if (!(ob->flags & O_DESTRUCTED)) { - fatal("Object 0x%lx %s ref count 0, but not destructed.\n" - , (long)ob, get_txt(ob->name)); + fatal("Object %p %s ref count 0, but not destructed.\n" + , ob, get_txt(ob->name)); } #endif /* DEBUG */ if (ob->sent) - fatal("free_object: Object '%s' (ref %ld, flags %08x) " + fatal("free_object: Object '%s' (ref %"PRIdPINT", flags %08x) " "still has sentences.\n" , get_txt(ob->name), ob->ref, ob->flags); @@ -311,12 +312,12 @@ dealloc_object ( object_t *ob, const char * file, int line) #ifdef CHECK_OBJECT_STAT if (check_object_stat) { - fprintf(stderr, "DEBUG: OSTAT: (%ld:%ld) free( %p '%s') with %d vars : %ld -> (%ld:%ld)\n" + fprintf(stderr, "DEBUG: OSTAT: (%ld:%ld) free( %p '%s') with %hu vars : %"PRIuPINT" -> (%ld:%ld)\n" , tot_alloc_object, tot_alloc_object_size, ob, ob->name ? get_txt(ob->name) : "" , prog->num_variables - , (long)(prog->num_variables * sizeof (svalue_t) + sizeof (object_t)) - , (long)tot_alloc_object - , (long)(tot_alloc_object_size - (prog->num_variables * sizeof (svalue_t) + sizeof (object_t))) + , (p_uint)(prog->num_variables * sizeof (svalue_t) + sizeof (object_t)) + , tot_alloc_object + , (tot_alloc_object_size - (prog->num_variables * sizeof (svalue_t) + sizeof (object_t))) ); } #endif @@ -348,7 +349,7 @@ dealloc_object ( object_t *ob, const char * file, int line) #ifdef CHECK_OBJECT_STAT if (check_object_stat) { - fprintf(stderr, "DEBUG: OSTAT: (%ld:%ld) free( %p '%s') with name : %ld -> (%ld:%ld)\n" + fprintf(stderr, "DEBUG: OSTAT: (%ld:%ld) free( %p '%s') with name : %zu -> (%ld:%ld)\n" , tot_alloc_object, tot_alloc_object_size, ob, get_txt(ob->name) , mstrsize(ob->name) , tot_alloc_object-1 @@ -422,12 +423,12 @@ static mp_int last_id = 0; #ifdef CHECK_OBJECT_STAT if (check_object_stat) { - fprintf(stderr, "DEBUG: OSTAT: (%ld:%ld) new( %p ) with %d vars : %ld -> (%ld:%ld)\n" + fprintf(stderr, "DEBUG: OSTAT: (%ld:%ld) new( %p ) with %d vars : %zu -> (%ld:%"PRIuPINT")\n" , tot_alloc_object, tot_alloc_object_size, ob , num_var - , (long)(size2+size) + , (size2+size) , tot_alloc_object+1 - , tot_alloc_object_size + size + size2 + , (p_uint)tot_alloc_object_size + size + size2 ); } #endif @@ -474,11 +475,13 @@ static mp_int last_id = 0; /*-------------------------------------------------------------------------*/ void -init_object_variables (object_t *ob) +init_object_variables (object_t *ob, object_t *templ) /* The variables of object are initialized. + * * First, if is a clone, all variables marked as !VAR_INITIALIZED are - * copied over from the blueprint. + * copied over from the , if given. MUST be the blueprint + * object. * * Then, for all , __INIT() is called in which initializes all * the variables marked as VAR_INITIALIZED in clones, and all variables @@ -489,20 +492,14 @@ init_object_variables (object_t *ob) /* For clones, copy the shared variable values */ if ((ob->flags & O_CLONE)) { - object_t *bp; int i; variable_t *p_vars; - svalue_t *ob_vars, *bp_vars; + svalue_t *ob_vars, *templ_vars; - bp = ob->prog->blueprint; - if (!bp || bp->flags & O_DESTRUCTED) - { - if (bp) free_object(bp, "init_object_variables"); - ob->prog->blueprint = NULL; - bp_vars = NULL; - } + if (!templ || templ->flags & O_DESTRUCTED) + templ_vars = NULL; else - bp_vars = bp->variables; + templ_vars = templ->variables; ob_vars = ob->variables; p_vars = ob->prog->variables; @@ -511,10 +508,10 @@ init_object_variables (object_t *ob) { if (p_vars[i].type.typeflags & VAR_INITIALIZED) continue; - if (!bp_vars) - errorf("Can't initialize object '%s': no blueprint.\n" + if (!templ_vars) + errorf("Can't initialize object '%s': no blueprint given.\n" , get_txt(ob->name)); - assign_svalue_no_free(&ob_vars[i], &bp_vars[i]); + assign_svalue_no_free(&ob_vars[i], &templ_vars[i]); } } @@ -566,7 +563,7 @@ reference_prog (program_t *progp, char *from) progp->ref++; #ifdef DEBUG_REFS if (d_flag) - printf("%s reference_prog: %s ref %ld (%s)\n" + printf("%s reference_prog: %s ref %"PRIdPINT" (%s)\n" , time_stamp(), get_txt(progp->name), progp->ref, from); #endif } @@ -656,7 +653,7 @@ _free_prog (program_t *progp, Bool free_all, const char * file, int line #if 0 && defined(CHECK_OBJECT_REF) if (strchr(get_txt(progp->name), '#') == NULL) - printf("DEBUG: (%s:%d) free_prog(%p '%s') ref %ld\n" + printf("DEBUG: (%s:%d) free_prog(%p '%s') ref %"PRIdPINT"\n" , file, line, progp, get_txt(progp->name), progp->ref); #endif #ifdef DEBUG_REFS @@ -664,7 +661,9 @@ _free_prog (program_t *progp, Bool free_all, const char * file, int line printf("%s free_prog: %s\n", time_stamp(), get_txt(progp->name)); #endif if (progp->ref < 0) - fatal("Negative ref count for prog ref.\n"); + fatal("Negative ref count (%"PRIdPINT") for prog ref " + "(program %p '%s').\n", + progp->ref, progp, get_txt(progp->name)); if (free_all && progp->blueprint) { @@ -675,7 +674,8 @@ _free_prog (program_t *progp, Bool free_all, const char * file, int line #endif #if 0 && defined(CHECK_OBJECT_REF) if (strchr(get_txt(blueprint->name), '#') == NULL) - printf("DEBUG: (%s:%d) free_prog(%p '%s') ref %ld : blueprint (%p '%s') ref %ld, flags %x\n" + printf("DEBUG: (%s:%d) free_prog(%p '%s') ref %"PRIdPINT" : " + "blueprint (%p '%s') ref %"PRIdPINT", flags %hx\n" , file, line, progp, get_txt(progp->name), progp->ref , blueprint, get_txt(blueprint->name), blueprint->ref, blueprint->flags); #elif defined(CHECK_OBJECT_REF) @@ -960,7 +960,8 @@ logon_object (object_t *ob) ret = apply(STR_LOGON, ob, 0); if (ret == 0) { - errorf("Could not find %s() on the player %s\n", get_txt(STR_LOGON), get_txt(ob->name)); + errorf("Could not find %s() on the player %s\n", get_txt(STR_LOGON), + get_txt(ob->name)); /* NOTREACHED */ } current_object = save; @@ -1042,10 +1043,10 @@ replace_programs (void) #ifdef CHECK_OBJECT_STAT if (check_object_stat) { - fprintf(stderr, "DEBUG: OSTAT: (%ld:%ld) rprog( %p '%s') sub %d vars : %ld -> (%ld:%ld)\n" + fprintf(stderr, "DEBUG: OSTAT: (%ld:%ld) rprog( %p '%s') sub %d vars : %"PRIuPINT" -> (%ld:%ld)\n" , tot_alloc_object, tot_alloc_object_size, r_ob, r_ob->ob->name ? get_txt(r_ob->ob->name) : "" , i - , (long)(i * sizeof(svalue_t)) + , (p_uint)(i * sizeof(svalue_t)) , tot_alloc_object, tot_alloc_object_size - (i * sizeof(svalue_t)) ); } @@ -1103,6 +1104,19 @@ replace_programs (void) r_ob->ob->variables = new_vars; } /* if (change in vars) */ + /* If the object modified is a blueprint object, NULL out the pointer + * in its program, because after the replacement the blueprint nature + * will be lost. + */ + if (r_ob->ob->prog->blueprint == r_ob->ob) + { + r_ob->ob->prog->blueprint = NULL; +#ifdef USE_SWAP + remove_prog_swap(r_ob->ob->prog, MY_TRUE); +#endif + free_object(r_ob->ob, "replace_programs: blueprint reference"); + } + /* Replace the old program with the new one */ old_prog = r_ob->ob->prog; r_ob->new_prog->ref++; @@ -1222,7 +1236,7 @@ search_inherited (string_t *str, program_t *prg, int *offpnt) debug_message("%s search_inherited started\n", ts); debug_message("%s searching for PRG(%s) in PRG(%s)\n" , ts, get_txt(str), get_txt(prg->name)); - debug_message("%s num_inherited=%d\n", ts, prg->num_inherited); + debug_message("%s num_inherited=%hu\n", ts, prg->num_inherited); } #endif @@ -1331,36 +1345,6 @@ tell_object (object_t *ob, string_t *str) tell_npc(ob, str); } -#if 0 -/*-------------------------------------------------------------------------*/ -void -tell_object_str (object_t *ob, const char *str) - -/* Send message to object . If is an interactive player, - * it will go to his screen (unless a shadow catches it - see shadow_catch_ - * message() ). If is not interactive, the message will go - * to the lfun 'catch_tell()' via a call to tell_npc(). - */ - -{ - object_t *save_command_giver; - interactive_t *ip; - - if (ob->flags & O_DESTRUCTED) - return; - - if (O_SET_INTERACTIVE(ip, ob)) - { - save_command_giver = command_giver; - command_giver = ob; - add_message("%s", str); - command_giver = save_command_giver; - return; - } - tell_npc_str(ob, str); -} -#endif - /*-------------------------------------------------------------------------*/ #ifdef USE_SHADOWING Bool @@ -1551,7 +1535,7 @@ v_function_exists (svalue_t *sp, int num_arg) { string_t *str, *prog_name; uint32 prog_line = 0; - uint32 flags; + p_int flags; svalue_t *argp; object_t *ob; @@ -1582,8 +1566,9 @@ v_function_exists (svalue_t *sp, int num_arg) || (flags & ~NAME_HIDDEN) > FEXISTS_ALL ) { - errorf("Bad argument 2 to function_exists(): value %ld (%ld sans NAME_HIDDEN) out of range %d..%d .\n" - , (long)flags, (long)(flags & ~NAME_HIDDEN) + errorf("Bad argument 2 to function_exists(): value %"PRIdPINT + " (%"PRIdPINT" sans NAME_HIDDEN) out of range %d..%d .\n" + , flags, (flags & ~NAME_HIDDEN) , FEXISTS_ALL, FEXISTS_LINENO); /* NOTREACHED */ return sp; @@ -1614,8 +1599,8 @@ v_function_exists (svalue_t *sp, int num_arg) || ((flags & ~NAME_HIDDEN) > FEXISTS_ALL) ) { - errorf("Bad argument 3 to function_exists(): eff. value %ld (sans NAME_HIDDEN) out of range %d..%d .\n" - , (long)(flags & ~NAME_HIDDEN) + errorf("Bad argument 3 to function_exists(): eff. value %"PRIdPINT" (sans NAME_HIDDEN) out of range %d..%d .\n" + , (flags & ~NAME_HIDDEN) , FEXISTS_PROGNAME, FEXISTS_ALL); /* NOTREACHED */ return sp; @@ -1706,8 +1691,8 @@ v_function_exists (svalue_t *sp, int num_arg) break; default: - fatal("function_exists(): flags value %ld (from %ld) not implemented.\n" - , (long)(flags & ~NAME_HIDDEN), (long)flags); + fatal("function_exists(): flags value %"PRIdPINT" (from %"PRIdPINT") not implemented.\n" + , (flags & ~NAME_HIDDEN), flags); /* NOTREACHED */ } } @@ -2073,8 +2058,8 @@ v_variable_exists (svalue_t *sp, int num_arg) if (mode_flags != 0 && mode_flags != NAME_HIDDEN) { errorf("Bad argument 2 to variable_exists(): " - "value %ld, expected 0 or %d (NAME_HIDDEN).\n" - , (long)mode_flags, NAME_HIDDEN + "value %"PRIdPINT", expected 0 or %d (NAME_HIDDEN).\n" + , mode_flags, NAME_HIDDEN ); /* NOTREACHED */ return sp; @@ -2105,8 +2090,8 @@ v_variable_exists (svalue_t *sp, int num_arg) if (mode_flags != 0 && mode_flags != NAME_HIDDEN) { errorf("Bad argument 3 to variable_exists(): " - "value %ld, expected 0 or %d (NAME_HIDDEN).\n" - , (long)mode_flags, NAME_HIDDEN + "value %"PRIdPINT", expected 0 or %d (NAME_HIDDEN).\n" + , mode_flags, NAME_HIDDEN ); /* NOTREACHED */ return sp; @@ -2743,8 +2728,8 @@ v_include_list (svalue_t *sp, int num_arg) if (!str) { free_array(vec); - errorf("(include_list) Out of memory: (%lu bytes) for filename\n" - , (unsigned long)slen); + errorf("(include_list) Out of memory: (%zu bytes) for filename\n" + , slen); } put_string(vec->item, str); @@ -2928,8 +2913,8 @@ v_inherit_list (svalue_t *sp, int num_arg) { free_array(vec); mempool_delete(pool); - errorf("(inherit_list) Out of memory: (%lu bytes) for filename\n" - , (unsigned long)slen); + errorf("(inherit_list) Out of memory: (%zu bytes) for filename\n" + , slen); } put_string(svp, str); } @@ -2977,8 +2962,8 @@ v_inherit_list (svalue_t *sp, int num_arg) if (!str) { mempool_delete(pool); - errorf("(inherit_list) Out of memory: (%lu bytes) for filename\n" - , (unsigned long)slen); + errorf("(inherit_list) Out of memory: (%zu bytes) for filename\n" + , slen); } /* If this child has no inherits, we just copy the @@ -3120,8 +3105,8 @@ f_load_name (svalue_t *sp) len = (size_t)(hash - get_txt(s)); p = mem = xalloc(len+1); if (!p) - errorf("(load_name) Out of memory (%lu bytes) for filename." - , (long)len+1); + errorf("(load_name) Out of memory (%zu bytes) for filename." + , len+1); strncpy(p, get_txt(s), len); p[len] = '\0'; @@ -3359,10 +3344,11 @@ f_rename_object (svalue_t *sp) */ { - object_t *ob; - char *name; - string_t *m_name; - mp_int length; + object_t *ob; /* object to be renamed */ + char *name; /* new name as c-string */ + string_t *m_name; /* new name */ + size_t length; /* length of new name */ + Bool freenamebuffer = MY_FALSE; /* free name when not needed */ inter_sp = sp; /* this is needed for assert_master_ob_loaded(), and for * the possible errors before. @@ -3379,12 +3365,18 @@ f_rename_object (svalue_t *sp) if (name[length-2] == '.' && name[length-1] == 'c') { /* A new writeable copy of the name is needed. */ char *p; - p = (char *)alloca(length+1); + p = xalloc(length+1); + if (!p) + errorf("Out of memory for %zu bytes in rename_object().\n", + length+1); + strcpy(p, name); name = p; name[length -= 2] = '\0'; + freenamebuffer = MY_TRUE; } + /* check for any #xxx at the end. */ { char c; char *p; @@ -3398,6 +3390,8 @@ f_rename_object (svalue_t *sp) if ( (c = *--p) < '0' || c > '9' ) { if (c == '#' && length - i > 1) { + if (freenamebuffer) + xfree(name); errorf("Illegal name to rename_object: '%s'.\n", name); } break; @@ -3405,18 +3399,38 @@ f_rename_object (svalue_t *sp) } } - assert_master_ob_loaded(); - if (master_ob == ob) - errorf("Attempt to rename the master object\n"); - m_name = new_mstring(name); if (!m_name) - errorf("Out of memory for object name (%ld bytes)\n", (long)strlen(name)); + { + if (freenamebuffer) + xfree(name); + errorf("Out of memory for object name (%zu bytes)\n", strlen(name)); + } + /* in case of errors (e.g. in privilege_violation()), push string on the + * stack. */ + push_string(sp, m_name); + inter_sp = sp; + /* name is not needed anymore. Free it, if it was allocated here. */ + if (freenamebuffer) + { + xfree(name); + /* just to be sure it crashes if somebody uses the pointer by + * accident. */ + name = NULL; + } + + assert_master_ob_loaded(); + if (master_ob == ob) + { + errorf("Attempt to rename the master object\n"); + } + + if (lookup_object_hash(m_name)) { - free_mstring(m_name); - errorf("Attempt to rename to existing object '%s'\n", name); + errorf("Attempt to rename to existing object '%s'\n", + get_txt(m_name)); } if (privilege_violation4(STR_RENAME_OBJECT, ob, m_name, 0, sp) @@ -3426,13 +3440,15 @@ f_rename_object (svalue_t *sp) remove_object_hash(ob); free_mstring(ob->name); ob->name = m_name; + // m_name needs another reference (one from the stack, one from + // object->name). + ref_mstring(m_name); enter_object_hash(ob); } - else - free_mstring(m_name); - free_svalue(sp--); - free_svalue(sp--); + /* free the string m_name (on the top of the stack) and the 2 arguments */ + sp = pop_n_elems(3, sp); + return sp; } /* f_rename_object() */ @@ -3481,6 +3497,7 @@ v_replace_program (svalue_t *sp, int num_arg) errorf("replace_program called with no current object\n"); if (current_object == simul_efun_object) errorf("replace_program on simul_efun object\n"); + if (current_object->flags & O_LAMBDA_REFERENCED) { inter_sp = sp; @@ -3489,11 +3506,7 @@ v_replace_program (svalue_t *sp, int num_arg) , get_txt(current_object->name) , get_txt(current_prog->name) ); - for ( ; num_arg != 0; num_arg--) - { - free_svalue(sp); - sp--; - } + sp = pop_n_elems(num_arg, sp); return sp; } @@ -3540,21 +3553,39 @@ v_replace_program (svalue_t *sp, int num_arg) else { string_t *sname; - long name_len; - char *name; - - /* Create the full program name with a trailing '.c' and without - * a leading '/' to match the internal name representation. - */ - name_len = (long)mstrsize(sp->u.str); - name = alloca((size_t)name_len+3); - strcpy(name, get_txt(sp->u.str)); - if (name[name_len-2] != '.' || name[name_len-1] != 'c') - strcat(name,".c"); - if (*name == '/') - name++; - memsafe(sname = new_mstring(name), name_len+3, "normalized program name"); + { /* block for limiting the scope of name until the xfree. */ + size_t name_len; + char *name; + /* Create the full program name with a trailing '.c' and without + * a leading '/' to match the internal name representation. + */ + name_len = mstrsize(sp->u.str); + name = xalloc(name_len+3); + if (!name) + { + errorf("Out of memory (%zu bytes) for temporary name buffer in " + "replace_program.\n", name_len); + } + strcpy(name, get_txt(sp->u.str)); + if (name[name_len-2] != '.' || name[name_len-1] != 'c') + strcat(name,".c"); + if (*name == '/') + sname = new_mstring(name+1); + else + sname = new_mstring(name); + /* name is not needed anymore, free it first, before throwing any + * runtime errors. */ + xfree(name); + + /* now check if we got a string from new_mstring(). */ + if (!sname) + { + errorf("Out of memory (%zu bytes) for temporary name in " + "replace_program().\n", name_len+3); + } + } /* scope of name ends here */ + new_prog = search_inherited(sname, current_object->prog, offsets); if (!new_prog) { @@ -4664,8 +4695,7 @@ e_say (svalue_t *v, vector_t *avoid) object_t *ob; object_t *save_command_giver = command_giver; object_t *origin; - char *message; - const char *format = "%s"; + string_t *message; #define INITIAL_MAX_RECIPIENTS 48 int max_recipients = INITIAL_MAX_RECIPIENTS; /* Current size of the recipients table. @@ -4684,7 +4714,6 @@ e_say (svalue_t *v, vector_t *avoid) &first_recipients[INITIAL_MAX_RECIPIENTS-1]; /* Last entry in the current table. */ - object_t *save_again; /* Determine the command_giver to use */ if (current_object->flags & O_ENABLE_COMMANDS) @@ -4790,8 +4819,7 @@ e_say (svalue_t *v, vector_t *avoid) switch(v->type) { case T_STRING: - format = FMT_STRING; - message = (char *)(v->u.str); + message = v->u.str; break; case T_OBJECT: @@ -4838,22 +4866,12 @@ e_say (svalue_t *v, vector_t *avoid) for (curr_recipient = recipients; NULL != (ob = *curr_recipient++); ) { - interactive_t *ip; - if (ob->flags & O_DESTRUCTED) continue; stmp.u.ob = ob; if (lookup_key(&stmp, avoid) >= 0) continue; - if (!(O_SET_INTERACTIVE(ip, ob))) - { - tell_npc_str(ob, message); - continue; - } - save_again = command_giver; - command_giver = ob; - add_message(format, message); - command_giver = save_again; + tell_object (ob, message); } pop_stack(); /* free avoid alist */ @@ -4962,14 +4980,13 @@ e_tell_room (object_t *room, svalue_t *v, vector_t *avoid) { object_t *ob; - object_t *save_command_giver; int num_recipients = 0; object_t *some_recipients[20]; object_t **recipients; object_t **curr_recipient; - char *message; - const char *format = "%s"; + string_t *message; static svalue_t stmp = { T_OBJECT, } ; + interactive_t *ip; /* Like in say(), collect the possible recipients. * First count how many there are. @@ -4977,14 +4994,18 @@ e_tell_room (object_t *room, svalue_t *v, vector_t *avoid) for (ob = room->contains; ob; ob = ob->next_inv) { - interactive_t *ip; - if ( ob->flags & O_ENABLE_COMMANDS || O_SET_INTERACTIVE(ip, ob)) { num_recipients++; } } + /* The room/environment itself? */ + if (room->flags & O_ENABLE_COMMANDS + || O_SET_INTERACTIVE(ip, room)) + { + num_recipients++; + } /* Allocate the table */ if (num_recipients < 20) @@ -4995,10 +5016,15 @@ e_tell_room (object_t *room, svalue_t *v, vector_t *avoid) /* Now fill the table */ curr_recipient = recipients; + /* The room/environment itself? */ + if (room->flags & O_ENABLE_COMMANDS + || O_SET_INTERACTIVE(ip, room)) + { + *curr_recipient++ = room; + } + /* now the objects in the room/container */ for (ob = room->contains; ob; ob = ob->next_inv) { - interactive_t *ip; - if ( ob->flags & O_ENABLE_COMMANDS || O_SET_INTERACTIVE(ip, ob)) { @@ -5012,8 +5038,7 @@ e_tell_room (object_t *room, svalue_t *v, vector_t *avoid) switch(v->type) { case T_STRING: - format = FMT_STRING; - message = (char *)(v->u.str); + message = v->u.str; break; case T_OBJECT: @@ -5066,20 +5091,10 @@ e_tell_room (object_t *room, svalue_t *v, vector_t *avoid) for (curr_recipient = recipients; NULL != (ob = *curr_recipient++); ) { - interactive_t *ip; - if (ob->flags & O_DESTRUCTED) continue; stmp.u.ob = ob; if (lookup_key(&stmp, avoid) >= 0) continue; - if (!(O_SET_INTERACTIVE(ip, ob))) - { - tell_npc_str(ob, message); - continue; - } - save_command_giver = command_giver; - command_giver = ob; - add_message(format, message); - command_giver = save_command_giver; + tell_object(ob, message); } } /* e_tell_room() */ @@ -5540,7 +5555,7 @@ f_transfer (svalue_t *sp) static Bool save_svalue(svalue_t *, char, Bool); static int restore_size(char **str); -static int restore_svalue(svalue_t *, char **, char); +static Bool restore_svalue(svalue_t *, char **, char); static void register_svalue(svalue_t *); /*-------------------------------------------------------------------------*/ @@ -5886,7 +5901,7 @@ save_mapping (mapping_t *m) MY_PUTC(':') source = number_buffer; - (void)sprintf(source, "%ld", (long)m->num_values); + (void)sprintf(source, "%"PRIdPINT, m->num_values); c = *source++; do MY_PUTC(c) while ( '\0' != (c = *source++) ); } @@ -5903,7 +5918,7 @@ save_array (vector_t *v) */ { - long i; + p_int i; svalue_t *val; /* Recall the array from the pointer table. @@ -5921,7 +5936,7 @@ save_array (vector_t *v) } /* ... the values ... */ - for (i = (long)VEC_SIZE(v), val = v->item; --i >= 0; ) + for (i = VEC_SIZE(v), val = v->item; --i >= 0; ) { save_svalue(val++, ',', MY_FALSE); } @@ -6098,17 +6113,19 @@ save_closure (svalue_t *cl, Bool writable) prog = inheritp->prog; progName = del_dotc(prog->name); - L_PUTC_PROLOG - source = get_txt(progName); - L_PUTC('|'); - c = *source++; - do { - if (issavedel(c)) - L_PUTC('\\'); - L_PUTC(c) - } while ( '\0' != (c = *source++) ); - L_PUTC_EPILOG + L_PUTC_PROLOG + source = get_txt(progName); + L_PUTC('|'); + c = *source++; + do + { + if (issavedel(c)) + L_PUTC('\\'); + L_PUTC(c) + } while ( '\0' != (c = *source++) ); + L_PUTC_EPILOG + } free_mstring(progName); } } @@ -6331,7 +6348,7 @@ save_svalue (svalue_t *v, char delimiter, Bool writable) char * source, c; source = number_buffer; - (void)sprintf(source, "#%hd:", v->x.quotes); + (void)sprintf(source, "#%"PRIdPHINT":", v->x.quotes); c = *source++; do L_PUTC(c) while ( '\0' != (c = *source++) ); L_PUTC_EPILOG @@ -6354,7 +6371,7 @@ save_svalue (svalue_t *v, char delimiter, Bool writable) char *source, c; source = number_buffer; - (void)sprintf(source, "%ld", v->u.number); + (void)sprintf(source, "%"PRIdPINT, v->u.number); c = *source++; do L_PUTC(c) while ( '\0' != (c = *source++) ); L_PUTC(delimiter); @@ -6392,7 +6409,7 @@ save_svalue (svalue_t *v, char delimiter, Bool writable) char *source, c; source = number_buffer; - (void)sprintf(source, "%.12e=%x:%lx" + (void)sprintf(source, "%.12e=%"PRIxPHINT":%"PRIxPINT , READ_DOUBLE(v), v->x.exponent & 0xffff , v->u.mantissa); c = *source++; @@ -6460,13 +6477,13 @@ register_array (vector_t *vec) { svalue_t *v; - long i; + p_int i; if (NULL == register_pointer(ptable, vec)) return; v = vec->item; - for (i = (long)VEC_SIZE(vec); --i >= 0; v++) + for (i = VEC_SIZE(vec); --i >= 0; v++) { register_svalue(v); } @@ -6506,7 +6523,7 @@ register_mapping_filter (svalue_t *key, svalue_t *data, void *extra) */ { - int i; + p_int i; register_svalue(key); @@ -6527,7 +6544,7 @@ register_mapping (mapping_t *map) { if (NULL == register_pointer(ptable, map)) return; - walk_mapping(map, register_mapping_filter, (void *)(p_int)map->num_values); + walk_mapping(map, register_mapping_filter, (void *)map->num_values); } /* register_mapping() */ /*-------------------------------------------------------------------------*/ @@ -6694,9 +6711,9 @@ v_save_object (svalue_t *sp, int numarg) { if (sp->u.number < -1 || sp->u.number > CURRENT_VERSION) { - errorf("Illegal value for arg 1 to save_object(): %ld, " + errorf("Illegal value for arg 1 to save_object(): %"PRIdPINT", " "expected -1..%d\n" - , (long)sp->u.number, CURRENT_VERSION + , sp->u.number, CURRENT_VERSION ); /* NOTREACHED */ return sp; @@ -6724,9 +6741,9 @@ v_save_object (svalue_t *sp, int numarg) if (sp->u.number < -1 || sp->u.number > CURRENT_VERSION) { - errorf("Illegal value for arg 2 to save_object(): %ld, " + errorf("Illegal value for arg 1 to save_object(): %"PRIdPINT", " "expected -1..%d\n" - , (long)sp->u.number, CURRENT_VERSION + , sp->u.number, CURRENT_VERSION ); /* NOTREACHED */ return sp; @@ -6735,7 +6752,8 @@ v_save_object (svalue_t *sp, int numarg) save_version = sp->u.number >= 0 ? sp->u.number : CURRENT_VERSION; - /* The main code wants sp == filename */ + /* The main code wants sp == filename (T_NUMBER svalues need no free.) + */ sp--; numarg--; break; @@ -6787,18 +6805,19 @@ v_save_object (svalue_t *sp, int numarg) /* Create the final and the temporary filename */ - len = (long)mstrsize(sfile); - name = alloca(len + (sizeof save_file_suffix) + - len + (sizeof save_file_suffix) + 4); - + inter_sp = sp; + name = xalloc_with_error_handler(len + (sizeof save_file_suffix) + + len + (sizeof save_file_suffix) + 4); if (!name) { free_mstring(sfile); - errorf("Stack overflow in save_object('%s')\n", get_txt(sp->u.str)); + errorf("Out of memory (%ld bytes) in save_object('%s')\n", + 2*len+2*sizeof(save_file_suffix)+4, get_txt(sp->u.str)); /* NOTREACHED */ return sp; } + sp = inter_sp; tmp_name = name + len + sizeof save_file_suffix; strcpy(name, get_txt(sfile)); @@ -6940,8 +6959,9 @@ v_save_object (svalue_t *sp, int numarg) close(f); unlink(tmp_name); add_message("Failed to save to file '%s'. Disk could be full.\n", file); - if (numarg) - sp = pop_n_elems(numarg, sp); + /* free the error handler and the arguments (numarg + 1 from sp). + */ + sp = pop_n_elems(numarg + 1, sp); sp++; put_number(sp, 1); return sp; @@ -6972,21 +6992,24 @@ v_save_object (svalue_t *sp, int numarg) unlink(tmp_name); #endif - if (numarg) - sp = pop_n_elems(numarg, sp); + /* free the error handler and the arguments (numarg + 1 from sp) and + * push result on the stack. + */ + sp = pop_n_elems(numarg + 1, sp); sp++; put_number(sp, i); - } + } /* if (file) */ else { /* Finish up the operation. Note that there propably is some * data pending in the save_buffer. */ - if (numarg) - sp = pop_n_elems(numarg, sp); + /* free the error handler and the arguments (numarg + 1 from sp). + */ + sp = pop_n_elems(numarg + 1, sp); + sp++; /* for the result */ - if (failed) put_number(sp, 0); /* Shouldn't happen */ else if (buf_left != SAVE_OBJECT_BUFSIZE) @@ -7084,9 +7107,9 @@ v_save_value (svalue_t *sp, int numarg) { if (sp->u.number < -1 || sp->u.number > CURRENT_VERSION) { - errorf("Illegal value for arg 1 to save_object(): %ld, " + errorf("Illegal value for arg 1 to save_object(): %"PRIdPINT", " "expected -1..%d\n" - , (long)sp->u.number, CURRENT_VERSION + , sp->u.number, CURRENT_VERSION ); /* NOTREACHED */ return sp; @@ -7201,6 +7224,9 @@ restore_map_size (struct rms_parameters *parameters) * * The function calls itself and restore_size() recursively * for embedded arrays and mappings. + * + * TODO: this function assumes that num_values and num_entries of mappings + * TODO::are 'int'. Should be changed to p_int. */ { @@ -7439,6 +7465,9 @@ restore_mapping (svalue_t *svp, char **str) * set to const0 in that case). * On a successful return, * is set to point after the mapping * restored. + * + * TODO: this function assumes that num_values and num_entries of mappings + * TODO::are 'int'. Should be changed to p_int. */ { @@ -7461,10 +7490,10 @@ restore_mapping (svalue_t *svp, char **str) if (max_mapping_size && siz * (1+tmp_par.num_values) > (p_int)max_mapping_size) { *svp = const0; - errorf("Illegal mapping size: %ld elements (%ld x %ld).\n" - , (long int)siz * (1+tmp_par.num_values) - , (long int)siz - , (long int)1+tmp_par.num_values ); + errorf("Illegal mapping size: %ld elements (%d x %d).\n" + , (long)siz * (1+tmp_par.num_values) + , siz + , 1+tmp_par.num_values ); return MY_FALSE; } @@ -7474,7 +7503,7 @@ restore_mapping (svalue_t *svp, char **str) if (!z) { *svp = const0; - errorf("(restore) Out of memory: mapping[%u, %u]\n" + errorf("(restore) Out of memory: mapping[%d, %d]\n" , siz, tmp_par.num_values); return MY_FALSE; } @@ -7528,6 +7557,9 @@ restore_size (char **str) * * The function calls itself and restore_map_size() recursively * for embedded arrays and mappings. + * + * TODO: this function assumes that the size of arrays and mappings is + * TODO::< INT_MAX. Should be changed to p_int. */ { @@ -7686,6 +7718,9 @@ restore_array (svalue_t *svp, char **str) * set to const0 in that case). * On a successful return, * is set to point after the array text * restored. + * + * TODO: this function assumes that the size of arrays is < INT_MAX. Should + * TODO::be changed to p_int. */ { @@ -8464,8 +8499,8 @@ Program terminated with signal 11, Segmentation fault. if (!svp->u.str) { *svp = const0; - errorf("(restore) Out of memory (%lu bytes) for string.\n" - , (unsigned long) strlen(start)); + errorf("(restore) Out of memory (%zu bytes) for string.\n" + , strlen(start)); } break; } @@ -8538,12 +8573,9 @@ Program terminated with signal 11, Segmentation fault. svp->type = T_FLOAT; if ( NULL != (cp = strchr(cp, '=')) && restored_host == CURRENT_HOST) { - int tmp; - cp++; - if (sscanf(cp, "%x:%lx", &tmp, &svp->u.mantissa) != 2) + if (sscanf(cp, "%"SCNxPHINT":%"SCNxPINT, &svp->x.exponent, &svp->u.mantissa) != 2) return 0; - svp->x.exponent = (short)tmp; } else { @@ -8604,8 +8636,8 @@ Program terminated with signal 11, Segmentation fault. current_shared_restored--; *svp = const0; errorf("(restore) Out of memory (%lu bytes) for " - "%lu shared values.\n" - , max_shared_restored * sizeof(svalue_t) + "%ld shared values.\n" + , (unsigned long)max_shared_restored * sizeof(svalue_t) , max_shared_restored); return MY_FALSE; } @@ -8687,8 +8719,8 @@ old_restore_string (svalue_t *v, char *str) if (!v->u.str) { *v = const0; - errorf("(restore) Out of memory (%lu bytes) for string\n" - , (unsigned long) strlen(str)); + errorf("(restore) Out of memory (%zu bytes) for string\n" + , strlen(str)); } return MY_TRUE; } @@ -8711,7 +8743,8 @@ typedef struct restore_cleanup_s { int * pNesting; /* The nesting counter */ char * buff; /* The optional allocated line buffer. */ FILE * f; /* The optional input file */ - struct discarded * dp; + struct discarded * dp; + char * filename; /* optional buffer for the filename */ /* List of values for which the variables no longer exist. */ } restore_cleanup_t; @@ -8745,6 +8778,10 @@ restore_object_cleanup ( svalue_t * arg) (*data->pNesting)--; free_shared_restored_values(); + + if (data->filename) + xfree(data->filename); + xfree(arg); } /* restore_object_cleanup() */ @@ -8790,6 +8827,7 @@ static int nesting = 0; /* Used to detect recursive calls */ size_t len; FILE *f; struct stat st; /* stat() info of the savefile */ + svalue_t *arg; /* pointer to the argument on the stack - for convenience */ int var_rest; /* Number of variables left after rover */ int num_var; /* Number of variables in the object */ @@ -8798,17 +8836,29 @@ static int nesting = 0; /* Used to detect recursive calls */ * to restore is searched from here, taking advantage of * the locality of save_object(). */ - restore_cleanup_t * rcp; /* Cleanup structure */ - -#define FREE_BUFF() MACRO( \ - if (nesting > 1) xfree(buff); else mb_free(mbFile); \ - ) - /* Free buff correctly. - */ - - + + arg = sp; + + /* Allocate memory for the error cleanup structure first. We need it + * anway and if we can't allocate it, then this is anyway a lost cause. */ + rcp = xalloc(sizeof(*rcp)); + if (!rcp) + { + errorf("(restore) Out of memory: (%zu bytes) for cleanup structure\n" + , sizeof(*rcp)); + /* NOTREACHED */ + return sp; + } + rcp->pNesting = &nesting; + rcp->buff = NULL; + rcp->f = NULL; + rcp->dp = NULL; + rcp->filename = NULL; + /* Push it on top of the argument on the stack. */ + sp = push_error_handler(restore_object_cleanup, &(rcp->head)); + /* Keep track of recursive calls */ nesting++; @@ -8819,17 +8869,18 @@ static int nesting = 0; /* Used to detect recursive calls */ ob = current_object; if (ob->flags & O_DESTRUCTED) { - free_svalue(sp); + sp = pop_n_elems(2, sp); /* pop and free error handler + argument */ + sp++; put_number(sp, 0); - nesting--; return sp; } + /* no need to restore objects without variables */ if (ob->prog->num_variables == 0) { - free_svalue(sp); + sp = pop_n_elems(2, sp); /* pop and free error handler + argument */ + sp++; put_number(sp, 1); - nesting--; return sp; } @@ -8839,24 +8890,25 @@ static int nesting = 0; /* Used to detect recursive calls */ file = NULL; f = NULL; lineno = 0; - if (get_txt(sp->u.str)[0] == '#') + if (get_txt(arg->u.str)[0] == '#') { /* We need a copy of the value string because we're * going to modify it a bit. */ - len = mstrsize(sp->u.str); + len = mstrsize(arg->u.str); buff = (nesting > 1) ? xalloc(len+1) : mb_alloc(mbFile, len+1); if (buff == NULL) { - nesting--; outofmem(len+1, "copy of value string"); } - memcpy(buff, get_txt(sp->u.str), len); + /* keep track of buff in the cleanup structure. */ + rcp->buff = buff; + memcpy(buff, get_txt(arg->u.str), len); buff[len] = '\0'; } else { - file = get_txt(sp->u.str); + file = get_txt(arg->u.str); } /* If restoring from a file, set it up */ @@ -8867,29 +8919,26 @@ static int nesting = 0; /* Used to detect recursive calls */ /* Get a valid filename */ - sfile = check_valid_path(sp->u.str, ob, STR_RESTORE_OBJECT, MY_FALSE); + sfile = check_valid_path(arg->u.str, ob, STR_RESTORE_OBJECT, MY_FALSE); if (sfile == NULL) { - nesting--; - errorf("Illegal use of restore_object('%s')\n", get_txt(sp->u.str)); + errorf("Illegal use of restore_object('%s')\n", get_txt(arg->u.str)); /* NOTREACHED */ return sp; } - /* Create the full filename */ - len = mstrsize(sfile); - name = alloca(len + (sizeof save_file_suffix)); - + name = xalloc(len + (sizeof save_file_suffix)); if (!name) { free_mstring(sfile); - nesting--; - errorf("Stack overflow in restore_object('%s')\n", get_txt(sp->u.str)); + errorf("Out of memory (%zu bytes) for filename buffer in " + "restore_object('%s')\n", len, get_txt(arg->u.str)); /* NOTREACHED */ return sp; } + rcp->filename = name; /* in case of errrors -> cleanup structure */ strcpy(name, get_txt(sfile)); if (name[len-2] == '.' && name[len-1] == 'c') @@ -8899,22 +8948,21 @@ static int nesting = 0; /* Used to detect recursive calls */ free_mstring(sfile); /* Open the file and gets its length */ - f = fopen(name, "r"); if (!f || fstat(fileno(f), &st) == -1) { if (f) fclose(f); - free_svalue(sp); + sp = pop_n_elems(2, sp); /* pop and free error handler + argument */ + sp++; put_number(sp, 0); - nesting--; return sp; } + rcp->f = f; /* keep track of f in case of errors */ if (st.st_size == 0) { - fclose(f); - free_svalue(sp); + sp = pop_n_elems(2, sp); /* pop and free error handler + argument */ + sp++; put_number(sp, 0); - nesting--; return sp; } FCOUNT_REST(name); @@ -8922,18 +8970,18 @@ static int nesting = 0; /* Used to detect recursive calls */ /* Allocate the linebuffer. Unfortunately, the whole file * can be one single line. */ - buff = (nesting > 1) ? xalloc((size_t)(st.st_size + 1)) : mb_alloc(mbFile, (size_t)(st.st_size+1)); if (!buff) { - fclose(f); - nesting--; - errorf("(restore) Out of memory (%lu bytes) for linebuffer.\n" - , (unsigned long) st.st_size+1); + /* TODO: st_size is off_t which is most often int64_t or int32_t. + * TODO:: PRIdMAX or PRId64 should be used, I think. */ + errorf("(restore) Out of memory (%ld bytes) for linebuffer.\n" + , (long) st.st_size+1); /* NOTREACHED */ return sp; } + rcp->buff = buff; } /* if (file) */ /* Initialise the variables */ @@ -8951,37 +8999,12 @@ static int nesting = 0; /* Used to detect recursive calls */ if (!shared_restored_values) { - if (f) - fclose(f); - FREE_BUFF(); - nesting--; errorf("(restore) Out of memory (%lu bytes) for shared values.\n" - , sizeof(svalue_t)*max_shared_restored); + , sizeof(svalue_t)*(unsigned long)max_shared_restored); /* NOTREACHED */ return sp; } - - /* Setup the error cleanup */ - inter_sp = sp; - rcp = xalloc(sizeof(*rcp)); - if (!rcp) - { - if (f) - fclose(f); - FREE_BUFF(); - nesting--; - errorf("(restore) Out of memory: (%lu bytes) for cleanup structure\n" - , (unsigned long)sizeof(*rcp)); - /* NOTREACHED */ - return sp; - } - - rcp->pNesting = &nesting; - rcp->buff = buff; - rcp->f = f; - rcp->dp = NULL; - push_error_handler(restore_object_cleanup, &(rcp->head)); - + num_var = ob->prog->num_variables; var_rest = 0; restored_version = -1; @@ -9041,7 +9064,8 @@ static int nesting = 0; /* Used to detect recursive calls */ } /* No version line: illegal format. - * Deallocate what we allocated so far and return. + * Most of the cleanup will be done by the error handler during + * stack unwinding. */ if (file) errorf("Illegal format (version line) when restoring %s " @@ -9174,24 +9198,29 @@ static int nesting = 0; /* Used to detect recursive calls */ , time_stamp(), get_txt(ob->name) , file ? name : "passed value"); - free_svalue(inter_sp--); /* calls the cleanup handler */ - - free_svalue(inter_sp); - put_number(inter_sp, 1); + free_svalue(sp--); /* calls the cleanup handler */ + free_svalue(sp); /* frees the argument */ + put_number(sp, 1); return sp; -#undef FREE_BUFF } /* f_restore_object() */ /*-------------------------------------------------------------------------*/ static void -restore_value_cleanup ( svalue_t * arg UNUSED) +restore_value_cleanup ( svalue_t * arg ) /* The error handler during restore value cleanup: free all resources. */ { + restore_cleanup_t * data = (restore_cleanup_t *) arg; + + if (data->buff) + xfree(data->buff); + free_shared_restored_values(); + + xfree(arg); } /* restore_value_cleanup() */ svalue_t * @@ -9210,7 +9239,7 @@ f_restore_value (svalue_t *sp) int restored_version; /* Formatversion of the saved data */ char *buff; /* The string to parse */ char *p; - svalue_t rcp; /* T_ERROR_HANDLER value */ + restore_cleanup_t *rcp; /* Cleanup structure */ /* The restore routines will put \0s into the string, so we * need to make a copy of all but malloced strings. @@ -9219,11 +9248,11 @@ f_restore_value (svalue_t *sp) size_t len; len = mstrsize(sp->u.str); - buff = alloca(len+1); + buff = xalloc(len+1); if (!buff) { - errorf("(restore) Out of stack (%lu bytes).\n" - , (unsigned long) len+1); + errorf("(restore) Out of memory (%zu bytes).\n" + , len+1); /* NOTREACHED */ return sp; } @@ -9234,6 +9263,45 @@ f_restore_value (svalue_t *sp) restored_version = -1; restored_host = -1; + /* Initialise the shared value table */ + + max_shared_restored = 64; + + if (shared_restored_values) + { + debug_message("(restore) Freeing lost shared_restored_values.\n"); + free_shared_restored_values(); + } + + shared_restored_values = xalloc(sizeof(svalue_t)*max_shared_restored); + if (!shared_restored_values) + { + xfree(buff); + errorf("(restore) Out of memory (%lu bytes) for shared values.\n" + , (unsigned long)max_shared_restored * sizeof(svalue_t)); + return sp; /* flow control hint */ + } + + current_shared_restored = 0; + + /* Place the result variable onto the stack */ + inter_sp = ++sp; + *sp = const0; + + /* Setup the error cleanup */ + rcp = xalloc(sizeof(*rcp)); + if (!rcp) + { + xfree(buff); + errorf("(restore) Out of memory (%zu bytes).\n" + , sizeof(*rcp)); + /* NOTREACHED */ + return sp; + } + rcp->buff = buff; + + push_error_handler(restore_value_cleanup, &(rcp->head)); + /* Check if there is a version line */ if (buff[0] == '#') { @@ -9248,39 +9316,14 @@ f_restore_value (svalue_t *sp) errorf("No data given.\n"); return sp-1; } - buff = p+1; + p++; } + else + p = buff; /* parse from beginning of buffer */ - /* Initialise the shared value table */ - - max_shared_restored = 64; - - if (shared_restored_values) - { - debug_message("(restore) Freeing lost shared_restored_values.\n"); - free_shared_restored_values(); - } - - shared_restored_values = xalloc(sizeof(svalue_t)*max_shared_restored); - if (!shared_restored_values) - { - errorf("(restore) Out of memory (%lu bytes) for shared values.\n" - , max_shared_restored * sizeof(svalue_t)); - return sp; /* flow control hint */ - } - - current_shared_restored = 0; - - /* Place the result variable onto the stack */ - inter_sp = ++sp; - *sp = const0; - - /* Setup the error cleanup */ - push_error_handler(restore_value_cleanup, &rcp); /* Now parse the value in buff[] */ - p = buff; if ( (restored_version < 0 && p[0] == '\"') ? !old_restore_string(sp, p) : !restore_svalue(sp, &p, '\n') diff --git a/src/object.h b/src/object.h index 1529285..9d88013 100644 --- a/src/object.h +++ b/src/object.h @@ -189,7 +189,7 @@ struct replace_ob_s # define ref_object(o,from) (\ (o)->ref++,\ - d_flag > 1 ? printf("Add ref to object %s: %ld (%s) %s %d\n" \ + d_flag > 1 ? printf("Add ref to object %s: %"PRIdPINT" (%s) %s %d\n" \ , get_txt((o)->name), (o)->ref, from, __FILE__, __LINE__) : 0, \ (o)) @@ -233,7 +233,7 @@ struct replace_ob_s object_t * tmp_ = o; \ if (tmp_->ref == 2) dest_last_ref_gone = MY_TRUE; \ tmp_->ref--;\ - if (d_flag > 1) printf("Sub ref from object %s: %ld (%s) %s %d\n"\ + if (d_flag > 1) printf("Sub ref from object %s: %"PRIdPINT" (%s) %s %d\n"\ , get_txt(tmp_->name), tmp_->ref, from, __FILE__, __LINE__);\ if (tmp_->ref <= 0) dealloc_object(tmp_); \ ) @@ -242,7 +242,7 @@ struct replace_ob_s object_t * tmp_ = o; \ if (tmp_->ref == 2) dest_last_ref_gone = MY_TRUE; \ tmp_->ref--;\ - if (d_flag > 1) printf("Sub ref from object %s: %ld (%s) %s %d\n"\ + if (d_flag > 1) printf("Sub ref from object %s: %"PRIdPINT" (%s) %s %d\n"\ , get_txt(tmp_->name), tmp_->ref, from, __FILE__, __LINE__);\ if (tmp_->ref <= 0) dealloc_object(tmp_, __FILE__, __LINE__); \ ) @@ -262,7 +262,7 @@ struct replace_ob_s #else # define deref_object(o,from) (--(o)->ref, \ - d_flag > 1 ? printf("Sub ref from object %s: %ld (%s)\n" \ + d_flag > 1 ? printf("Sub ref from object %s: %"PRIdPINT" (%s)\n" \ , get_txt((o)->name), (o)->ref, from) : 0) #endif @@ -321,7 +321,7 @@ extern void dealloc_object(object_t *); extern void dealloc_object(object_t *, const char * file, int line); #endif extern object_t *get_empty_object(int num_var); -extern void init_object_variables (object_t *ob); +extern void init_object_variables (object_t *ob, object_t *templ); extern svalue_t *v_function_exists(svalue_t *sp, int num_arg); extern svalue_t *f_functionlist(svalue_t *sp); diff --git a/src/otable.c b/src/otable.c index 504a465..24fe31e 100644 --- a/src/otable.c +++ b/src/otable.c @@ -51,10 +51,10 @@ #if !( (OTABLE_SIZE) & (OTABLE_SIZE)-1 ) # define ObjHash(s) (mstr_get_hash(s) & ((OTABLE_SIZE)-1) ) -# define ObjHashStr(s,len) (whashmem(s, len, MSTRING_HASH_LENGTH) & ((OTABLE_SIZE)-1) ) +# define ObjHashStr(s,len) (hash_string(s, len) & ((OTABLE_SIZE)-1) ) #else # define ObjHash(s) (mstr_get_hash(s) % OTABLE_SIZE) -# define ObjHashStr(s,len) (whashmem(s, len, MSTRING_HASH_LENGTH) % OTABLE_SIZE) +# define ObjHashStr(s,len) (hash_string(s, len) % OTABLE_SIZE) #endif /* Hash the string and compute the appropriate table index */ diff --git a/src/pkg-idna.c b/src/pkg-idna.c index 21ca9b1..e54e3a4 100644 --- a/src/pkg-idna.c +++ b/src/pkg-idna.c @@ -216,7 +216,7 @@ f_idna_stringprep (svalue_t *sp) { errorf("stringprep(): Error %s", stringprep_strerror(ret)); /* NOTREACHED */ - } + } else { // free the string argument diff --git a/src/pkg-iksemel.c b/src/pkg-iksemel.c new file mode 100644 index 0000000..d289b5d --- /dev/null +++ b/src/pkg-iksemel.c @@ -0,0 +1,560 @@ +/*------------------------------------------------------------------ + * iksemel Efuns + * + *------------------------------------------------------------------ + * This file holds the efuns interfacing with iksemel and provides + * functions for handling xml files and converting them between + * mappings and xml data strings. + * + * efun: xml_ + *------------------------------------------------------------------ + */ +#include "driver.h" + +#ifdef USE_IKSEMEL + +#include +#include "array.h" +#include "xalloc.h" +#include "mapping.h" +#include "mstrings.h" +#include "simulate.h" +#include "interpret.h" +#include "pkg-iksemel.h" +#include "typedefs.h" + +#include "../mudlib/sys/xml.h" + +typedef struct attribute_walk_extra_s attribute_walk_extra_t; + +/* This structure is used to walk all attributes as well as for error handling. + * In case an error happens, this structure is called too. + */ +struct attribute_walk_extra_s +{ + iks *node; + int size; + + char *tag_name; +}; + +/* This structure is used for error handling. In case of an error our handler + * called with a pointer ot this structure. + */ +struct xml_cleanup_s +{ + svalue_t head; /* push_error_handler saves the link to our handler here. */ + + iks *node; + iksparser *parser; +}; + +void * +iksemel_alloc(size_t size) +{ + return xalloc(size); +} + +void +iksemel_free(void *ptr) +{ + xfree(ptr); +} + +void +add_string_to_mapping(mapping_t *map, char *skey, char *svalue) + +/* + * Adds a string value under the given key to the given mapping. In case the + * value already exists, it is overriden. + */ +{ + svalue_t key; + svalue_t *value; + + /* change the c string into an string_t */ + put_c_string(&key, skey); + + /* get or insert key */ + value = get_map_lvalue(map, &key); + + /* free the string_t again */ + free_svalue(&key); + + /* free maybe existing value (should not happen, i hope) */ + free_svalue(value); + + /* change the value of the key to the given value */ + put_c_string(value, svalue); +} + +void +parse_node(svalue_t *result, iks *node) + +/* + * Parses the xml DOM starting at node and returns the information on the + * stack. + */ +{ + int i = 0; + int num_attributes = 0; + int num_children = 0; + + iks *attribute; + iks *child; + + vector_t *root = NULL; + vector_t *children = NULL; + mapping_t *attributes = NULL; + + /* lets figure out if the node is cdata or another tag */ + switch (iks_type(node)) + { + case IKS_NONE: + case IKS_ATTRIBUTE: + /* we ignore those, as they will not occure for us */ + + return; + case IKS_CDATA: + /* Add the string as result, and return */ + put_c_n_string(result, iks_cdata(node), iks_cdata_size(node)); + + return; + case IKS_TAG: + break; + } + + /* We have a tag here, so allocate a tag array with three elements + * (name, contents and attributes) + */ + memsafe(root = allocate_array(XML_TAG_SIZE), sizeof(*root), "new tag array"); + + /* Put the array as result */ + put_array(result, root); + + /* add name to array */ + put_c_string(&root->item[XML_TAG_NAME], iks_name(node)); + + /* check if the node has any children */ + child = iks_child(node); + if (child != NULL) + { + do + { + ++num_children; + } + while ((child = iks_next(child))); + } + + if (0 < num_children) + { + /* children need to stay in the right order, so we create another + * for them + */ + memsafe(children = allocate_array(num_children), sizeof(*children) + , "new tag contents array"); + + /* Add the array of all children to the node */ + put_array(&root->item[XML_TAG_CONTENTS], children); + + /* get the first child */ + child = iks_child(node); + + do + { + /* recurse here cause the child can be a string or another node */ + parse_node(&children->item[i++], child); + } + while ((child = iks_next(child))); + } + + /* Finally, lets handle the attributes, we need to find out how many + * attributes the node has, to allocate enough memory for them. If + * no attributes exist, the part in the array will be empty */ + + attribute = iks_attrib(node); + if (attribute != NULL) + { + do + { + ++num_attributes; + } + while ((attribute = iks_next(attribute))); + } + + if (0 < num_attributes) + { + /* allocate new mapping */ + memsafe(attributes = allocate_mapping(num_attributes, 1), sizeof(*attributes) + , "new attributes mapping"); + + /* add the attributes to the array */ + put_mapping(&root->item[XML_TAG_ATTRIBUTES], attributes); + + /* get the first one */ + attribute = iks_attrib(node); + + do + { + add_string_to_mapping(attributes, iks_name(attribute), iks_cdata(attribute)); + } + while ((attribute = iks_next(attribute))); + } +} + +void +walk_attribute_mapping(svalue_t *key, svalue_t *val, void *pextra) + +/* + * Callback for walk_mapping() used in generate_xml_node to add iks + * attribute nodes to the node given in the pextra. + */ +{ + char *ckey; + attribute_walk_extra_t *extra = pextra; + + if (key->type == T_STRING) + { + ckey = get_txt(key->u.str); + } + else + { + errorf("Bad argument 1 to xml_generate(): expected string for attribute key of tag '%s'.\n" + , extra->tag_name); + + /* NOTREACHED */ + return; + } + + if (val->type == T_STRING) + { + memsafe(iks_insert_attrib(extra->node, ckey, get_txt(val->u.str)) + , sizeof(*ckey), "new iksemel attribute"); + } + else + { + errorf("Bad argument 1 to xml_generate(): expected string for value of attribute '%s' of tag '%s'.\n" + , ckey, extra->tag_name); + } +} + +static void +xml_cleanup(svalue_t * arg) + +/* + * Takes care, that the node without parent (root node) is correctly freed in + * case of an error and at the end of the f_generate_xml(). + */ +{ + struct xml_cleanup_s * data; + + data = (struct xml_cleanup_s *)arg; + + if (data->node) + { + iks_delete(data->node); + } + + if (data->parser) + { + iks_parser_delete(data->parser); + } + + xfree(data); +} /* xml_cleanup() */ + +iks * +generate_xml_node(vector_t *vnode, iks *parent) + +/* + * Generates a new iks node from the given array structure with the three + * elements (name, contents, attributes) and adds the node to the parent, + * or in case this is empty, simply returns it. The contents element may + * contain other tags, so recursion may occur. + */ +{ + iks *node; + svalue_t *element; + char *name; + struct xml_cleanup_s * rec_data; + + if ((mp_int) VEC_SIZE(vnode) != 3) + { + errorf("Bad arg 1 to xml_generate(): tag is not an array with 3 " + "elements.\n"); + + /* NOTREACHED */ + return NULL; + } + + /* get the name, as this is essential */ + element = &vnode->item[XML_TAG_NAME]; + + if (element->type != T_STRING) + { + errorf("Bad arg 1 to xml_generate(): first element of tag array not a " + "string.\n"); + + /* NOTREACHED */ + return NULL; + } + + /* get the name */ + name = get_txt(element->u.str); + + /* depending whether there is a parent or not, we start the structure + * or add the node to the given one */ + if (parent == NULL) + { + memsafe(node = iks_new(name), 30, "new iksemel node"); + + rec_data = xalloc(sizeof(*rec_data)); + if (rec_data == NULL) + { + iks_delete(node); + + errorf("generate_xml() Out of memory: (%lu bytes) for cleanup structure\n" + , (unsigned long) sizeof(*rec_data)); + + /* NOTREACHED */ + return NULL; + } + rec_data->node = node; + rec_data->parser = NULL; + + push_error_handler(xml_cleanup, &(rec_data->head)); + } + else + { + memsafe(node = iks_insert(parent, name), 30, "insert new iksemel node"); + } + + /* now handle the attributes of this one */ + element = &vnode->item[XML_TAG_ATTRIBUTES]; + + /* this might be absent */ + if (element->type == T_MAPPING) + { + attribute_walk_extra_t extra; + + extra.node = node; + extra.size = element->u.map->num_values; + extra.tag_name = name; + + /* walk the mapping and add all attributes */ + walk_mapping(element->u.map, &walk_attribute_mapping, &extra); + } + else if (element->type != T_NUMBER || element->u.number != 0) + { + errorf("Bad arg 1 to xml_generate(): second element of tag array not " + "NULL/mapping.\n"); + + /* NOTREACHED */ + return NULL; + } + + /* now check, if the node has a contents */ + element = &vnode->item[XML_TAG_CONTENTS]; + + /* this might even be absent */ + if (element->type == T_POINTER) + { + int size; + int i; + vector_t *contents; + + /* get the vector */ + contents = element->u.vec; + + /* get its size */ + size = (mp_int)VEC_SIZE(contents); + + for (i = 0; i < size; i++) + { + element = &contents->item[i]; + + if (element->type == T_STRING) + { + /* found a cdata */ + memsafe(iks_insert_cdata(node, get_txt(element->u.str), mstrsize(element->u.str)) + , mstrsize(element->u.str) + , "new iksemel node cdata"); + } + else if (element->type == T_POINTER) + { + /* found a sub tag, as iks_insert will handle the insert we do + * not have anything to do with the result + */ + generate_xml_node(element->u.vec, node); + } + } + } + else if (element->type != T_NUMBER || element->u.number != 0) + { + errorf("Bad arg 1 to xml_generate(): third element of tag array not " + "NULL/array.\n"); + + /* NOTREACHED */ + return NULL; + } + + return node; +} + +void +pkg_iksemel_init() +{ + iks_set_mem_funcs(iksemel_alloc, iksemel_free); +} + +/*=========================================================================*/ + +/* EFUNS */ + +/*-------------------------------------------------------------------------*/ + +svalue_t * +f_xml_generate(svalue_t *sp) + +/* EFUN xml_generate() + * + * string xml_generate(mixed *xml) + * + * Converts the given array into an XML conform string, if + * possible. The argument array must have the same structure + * as xml_parse returns. + * + * In case the parameter does not follow these rules, errors are raised. + * The method returns a valid XML string otherwise. + */ +{ + char *xml_string; + iks *node; + vector_t *root; + + /* get the root of the structure to be used */ + root = sp->u.vec; + + /* start generating the tree */ + node = generate_xml_node(root, NULL); + + /* At this point generate_xml_node() had + put an error handler on the stack. + */ + + /* Clean up and return result */ + free_svalue(sp); + + /* get the xml string out of the stack */ + memsafe(xml_string = iks_string(iks_stack(node), node) + , sizeof(*xml_string), "new xml string from node"); + + /* send the xml string back onto the stack */ + put_c_string(sp, xml_string); + + /* clean up, this will free the root node too, as it calls our error handler */ + pop_stack(); + + return sp; +} + +svalue_t * +f_xml_parse(svalue_t * sp) + +/* EFUN xml_parse() + * + * mixed * xml_parse(string xml_text) + * + * Parses the given string as a XML conform string. The string must + * have only one root tag, subsequent root tags are ignored. + * + * If the xml string is correct, an array is of three elements is + * returned, where as the following indices are defined: + * + * string XML_TAG_NAME + * The name of the XML tag. + * + * mixed * XML_TAG_CONTENTS + * The contents of this xml tag as array. This array may + * contain either strings, or arrags of sub-tags again with + * three elements (see example) + * + * If the xml tag does not contain anything, the element is + * set 0. + * + * mapping XML_TAG_ATTRIBUTES + * All attributes given to the XML tag as mapping where the key + * is the attribute name and the value is its string value. + * + * If the xml tag does not contain any attributes, this element + * is set 0. + * + * If the XML string is not well formed, or there is not enough memory to + * parse the whole XML structure into the array an error is raised. In case + * the XML string can't be parsed, cause it is not valid XML, 0 is returned. + */ +{ + struct xml_cleanup_s * rec_data; + int err; + + memsafe(rec_data = xalloc(sizeof(*rec_data)), sizeof(*rec_data), "xml cleanup structure"); + rec_data->node = NULL; + rec_data->parser = NULL; + push_error_handler(xml_cleanup, &(rec_data->head)); + + /* TODO: This can be implemented more efficient using the SAX interface. */ + memsafe(rec_data->parser = iks_dom_new(&(rec_data->node)), 50, "new iksemel parser"); + + err = iks_parse(rec_data->parser, get_txt(sp->u.str), mstrsize(sp->u.str), 1); + switch (err) + { + case IKS_OK: + break; + + case IKS_NOMEM: + errorf("Out of memory.\n"); + + /* NOTREACHED */ + return sp; + + case IKS_BADXML: + errorf("Bad arg 1 to xml_parse(): XML document not well formed (error " + "in line %ld, byte %ld).\n", iks_nr_lines(rec_data->parser) + , iks_nr_bytes(rec_data->parser)); + + /* NOTREACHED */ + return sp; + + case IKS_HOOK: + /* actually only used for a sax parser? */ + + break; + } + + /* we no longer need the string */ + free_svalue(sp); + + /* set 0 to always have a valid return */ + put_number(sp, 0); + + if (rec_data->node != NULL) + { + /* tree contains the tree now, this will put the resulting a */ + parse_node(sp, rec_data->node); + } + else + { + /* There was no XML tag or the tag was not closed properly. */ + errorf("Bad arg 1 to xml_parse(): XML document not well formed (premature end " + "at line %ld, byte %ld).\n", iks_nr_lines(rec_data->parser) + , iks_nr_bytes(rec_data->parser)); + } + + /* At the end, be nice and remove the rest + using our error handler. */ + pop_stack(); + + return sp; +} + +#endif /* USE_IKSEMEL */ diff --git a/src/pkg-iksemel.h b/src/pkg-iksemel.h new file mode 100644 index 0000000..43f9313 --- /dev/null +++ b/src/pkg-iksemel.h @@ -0,0 +1,19 @@ +#ifndef PKG_IKSEMEL_H__ +#define PKG_IKSEMEL_H__ 1 + +#include "driver.h" + +#ifdef USE_IKSEMEL + +#ifndef HAS_IKSEMEL +#error "pkg-iksemel configured even though the machine doesn't support iksemel." +#endif + +/* --- Prototypes --- */ + +void pkg_iksemel_init(); + +#endif /* USE_IKSEMEL */ + +#endif /* PKG_IKSEMEL_H__ */ + diff --git a/src/pkg-mysql.c b/src/pkg-mysql.c index eac3900..182e303 100644 --- a/src/pkg-mysql.c +++ b/src/pkg-mysql.c @@ -381,15 +381,17 @@ f_db_conv_string (svalue_t *sp) char *buff; s = sp->u.str; - buff = alloca(mstrsize(s)*2 +1); + buff = xalloc(mstrsize(s)*2 +1); if ( !buff ) { - errorf("Out of memory.\n"); + errorf("Out of memory (%zu bytes) in db_conv_string().\n", + mstrsize(s)*2 + 1); /* NOTREACHED */ return sp; } mysql_escape_string(buff, get_txt(s), strlen(get_txt(s)) ); - + + xfree(buff); free_string_svalue(sp); put_c_string(sp, buff); return sp; diff --git a/src/pkg-pcre.h b/src/pkg-pcre.h index d30ca62..5e720d3 100644 --- a/src/pkg-pcre.h +++ b/src/pkg-pcre.h @@ -22,6 +22,10 @@ /* Error code to be returned if too many backtracks are detected. */ +#ifdef PCRE_ERROR_RECURSIONLIMIT +#define RE_ERROR_BACKTRACK PCRE_ERROR_RECURSIONLIMIT +#else #define RE_ERROR_BACKTRACK PCRE_ERROR_MATCHLIMIT +#endif #endif /* PKG_PCRE_H_ */ diff --git a/src/pkg-sqlite.c b/src/pkg-sqlite.c index b4f70a6..91279c1 100644 --- a/src/pkg-sqlite.c +++ b/src/pkg-sqlite.c @@ -74,7 +74,7 @@ struct sqlite_dbs_s /* The list of database connections. */ static sqlite_dbs_t *head = NULL; - + /*-------------------------------------------------------------------------*/ static sqlite_dbs_t * find_db (object_t * obj) @@ -150,29 +150,83 @@ remove_db(sqlite_dbs_t *db) /*-------------------------------------------------------------------------*/ static int -my_sqlite3_authorizer(void * data, int what, const char* arg1, const char* arg2, +my_sqlite3_authorizer (void * data, int what, const char* arg1, const char* arg2, const char* dbname, const char* view) /* Callback function for SQLite to handle authorizations. */ { - /* TODO: Check them via privilege_violation resp. valid_write. - (Don't know, whether sqlite can handle longjmps out of - its code in case of an error...) - */ - + struct error_recovery_info error_recovery_info; + svalue_t *save_sp, sarg1, sarg2; + struct control_stack *save_csp; + int val; + switch(what) { case SQLITE_PRAGMA: - if(!strcasecmp(arg1, "synchronous")) - return SQLITE_OK; - return SQLITE_DENY; + /* PRAGMA name [ = value ] + * PRAGMA function(arg) + * + * arg1: name/function + * arg2: value/arg + * dbname/view: NULL + */ + + error_recovery_info.rt.last = rt_context; + error_recovery_info.rt.type = ERROR_RECOVERY_APPLY; + rt_context = (rt_context_t *)&error_recovery_info; + + save_sp = inter_sp; + save_csp = csp; + sarg1.type = T_INVALID; + sarg2.type = T_INVALID; + + if (setjmp(error_recovery_info.con.text)) + { + secure_apply_error(save_sp, save_csp, MY_FALSE); + val = SQLITE_DENY; + } + else + { + if(arg1) + put_c_string(&sarg1, arg1); + else + put_number(&sarg1, 0); + + if(arg2) + put_c_string(&sarg2, arg2); + else + put_number(&sarg2, 0); + + if(privilege_violation2(STR_SQLITE_PRAGMA, &sarg1, &sarg2, inter_sp)) + val = SQLITE_OK; + else + val = SQLITE_DENY; + } + + free_svalue(&sarg1); + sarg1.type = T_INVALID; + free_svalue(&sarg2); + sarg2.type = T_INVALID; + + rt_context = error_recovery_info.rt.last; + + return val; case SQLITE_ATTACH: - case SQLITE_DETACH: + /* ATTACH "filename" AS "dbname" + * + * arg1: filename + * arg2, dbname, view: NULL + */ + + /* SQLite3 doesn't allow the filename to be changed, + * but at least we must convert an absolute pathname + * to a relative one. So we have to deactivate it... + */ return SQLITE_DENY; - + default: return SQLITE_OK; } @@ -323,13 +377,13 @@ v_sl_exec (svalue_t * sp, int num_arg) db = find_db (current_object); if (!db) errorf("The current object doesn't have a database open.\n"); - - /* To increase the efficiency of SQLite by avoid re-parsing of statements, - * these prepared (precompiled) statement objects should be cached and - * re-used whenever the command string is the same. The placeholder syntax - * of SQLite is defined at http://www.sqlite.org/c3ref/bind_blob.html - * See also http://about.psyc.eu/SQL -lynX 2008 - */ + + /* To increase the efficiency of SQLite by avoid re-parsing of statements, + * these prepared (precompiled) statement objects should be cached and + * re-used whenever the command string is the same. The placeholder syntax + * of SQLite is defined at http://www.sqlite.org/c3ref/bind_blob.html + * See also http://about.psyc.eu/SQL -lynX 2008 + */ err = sqlite3_prepare(db->db, get_txt(argp->u.str), mstrsize(argp->u.str), &stmt, &tail); if(err) @@ -380,8 +434,7 @@ v_sl_exec (svalue_t * sp, int num_arg) rec_data->rows = NULL; rec_data->stmt = stmt; - push_error_handler(sl_exec_cleanup, &(rec_data->head)); - sp = inter_sp; + sp = push_error_handler(sl_exec_cleanup, &(rec_data->head)); while((err = sqlite3_step(stmt)) == SQLITE_ROW) { diff --git a/src/port.c b/src/port.c index a7b9cbe..d371651 100644 --- a/src/port.c +++ b/src/port.c @@ -19,6 +19,7 @@ #ifdef HAVE_SYS_TIME_H #include #endif +#include #include #include "backend.h" @@ -86,24 +87,30 @@ get_current_time (void) /*-------------------------------------------------------------------------*/ char * -time_string (mp_int t) - -/* Return a textual representation of the time . */ - +time_fstring (mp_int t, const char* str, Bool localized) + +/* Return a textual representation of the time according to the format + * string . Doesn't cache because it would be necessary to + * save the format string and compare. + * If localized is true, this function sets the locale according to the + * environment variable before calling strftime and resets it afterwards. + * TODO: It would be nicer to allocate the result buffer dynamically + * TODO::for using longer format strings. */ { - static char result[80]; - struct tm *tm; - mp_int last_time = -1; - - if (t != last_time) - { - time_t ti = (time_t)t; - last_time = t; - tm = localtime(&ti); - strftime(result, sizeof(result)-1, "%a %b %d %H:%M:%S %Y", tm); + static char result[512]; + struct tm *tm; // broken-down time struct + time_t ti = (time_t)t; + tm = localtime(&ti); + if (!localized) { + setlocale(LC_TIME, "C"); + strftime(result, sizeof(result)-1, str, tm); + setlocale(LC_TIME, ""); } + else + strftime(result, sizeof(result)-1, str, tm); + return result; -} /* time_string() */ +} /* time_fstring() */ /*-------------------------------------------------------------------------*/ char * @@ -115,18 +122,13 @@ utime_string (mp_int t, mp_int ut) static char result[80]; struct tm *tm; size_t len; - mp_int last_t = -1, last_ut = -1; - if (t != last_t || ut != last_ut) - { - time_t ti = (time_t)t; - last_t= t; - last_ut= ut; - tm = localtime(&ti); - len = strftime(result, sizeof(result)-1, "%a %b %d %H:%M:%S:", tm); - sprintf(result+len, "%06ld", ut); - strftime(result+len+6, sizeof(result)-7-len, " %Y", tm); - } + time_t ti = (time_t)t; + tm = localtime(&ti); + len = strftime(result, sizeof(result)-1, "%a %b %d %H:%M:%S:", tm); + sprintf(result+len, "%06"PRIdMPINT, ut); + strftime(result+len+6, sizeof(result)-7-len, " %Y", tm); + return result; } /* utime_string() */ @@ -154,8 +156,8 @@ time_stamp (void) time_t ti = (time_t)t; last_time = t; tm = localtime(&ti); - strftime( current_time_stamp, sizeof(current_time_stamp)-1 - , "%Y.%m.%d %H:%M:%S", tm); + strftime( current_time_stamp, sizeof(current_time_stamp), + "%Y.%m.%d %H:%M:%S", tm); } return current_time_stamp; } /* time_stamp() */ diff --git a/src/port.h b/src/port.h index f2cf149..fa4db21 100644 --- a/src/port.h +++ b/src/port.h @@ -87,12 +87,7 @@ extern int errno; #if !defined(STDC_HEADERS) && defined(HAVE_MEMORY_H) # include #endif -#if 0 -/* TODO: Obsoleted by limits.h+floats.h - remove this and the config check */ -#ifdef HAVE_VALUES_H -# include -#endif -#endif + #ifdef HAVE_STDLIB_H # include #endif @@ -121,35 +116,6 @@ extern int errno; # include #endif - -/*------------------------------------------------------------------ - * Limits for less-standard integral types: - * - * LONGLONG_MIN, LONGLONG_MAX, ULONGLONG_MAX - * TODO: Add SIZEOF_SIZET to configure, and SIZET_limits here. - * TODO:: Then use SIZET_limits in smalloc::smalloc(). - */ - -#if defined(HAVE_LONG_LONG) && !defined(LONGLONG_MIN) -# if defined(LONG_LONG_MAX) -# define LONGLONG_MIN LONG_LONG_MIN -# define LONGLONG_MAX LONG_LONG_MAX -# define ULONGLONG_MAX ULONG_LONG_MAX -# elif SIZEOF_LONG_LONG == 8 -# define LONGLONG_MIN (-9223372036854775807LL - 1) -# define LONGLONG_MAX (9223372036854775807LL) -# define ULONGLONG_MAX (0xffffffffffffffffULL) -# elif SIZEOF_LONG_LONG == SIZEOF_LONG -# define LONGLONG_MIN LONG_MIN -# define LONGLONG_MAX LONG_MAX -# define ULONGLONG_MAX ULONG_MAX -# elif SIZEOF_LONG_LONG == SIZEOF_INT -# define LONGLONG_MIN INT_MIN -# define LONGLONG_MAX INT_MAX -# define ULONGLONG_MAX UINT_MAX -# endif -#endif - /*------------------------------------------------------------------ * Define some macros: * CHAR_BIT number of bits in a char, if not defined already. @@ -184,31 +150,35 @@ extern int errno; # endif #endif -#if defined(__GNUC__) && __GNUC__ >= 2 && (__GNUC_MINOR__ > 6 || __GNUC__ > 2) -# define NORETURN __attribute__ ((noreturn)) -# define UNUSED __attribute__ ((unused)) +/* some handy gcc attributes, but define everything to nothing if any other + * compiler ist used. Additional attributes maybe used in the driver are: + always_inline, const, deprecated, format_arg, nonnull, pure, returns_twice, + unused, warn_unused_result. + */ +#if defined(__GNUC__) +# define MALLOC __attribute__((malloc)) +# define NORETURN __attribute__((noreturn)) +# define UNUSED __attribute__((unused)) +# define FORMATDEBUG(f,a,b) __attribute__((format (f,a,b))) #elif defined(__MWERKS__) +# define __attribute__(x) /*NOTHING*/ # define NORETURN # define UNUSED -#else -# define NORETURN -# define UNUSED -#endif - -#if defined(__GNUC__) && __GNUC__ >= 3 -# define MALLOC __attribute__ ((malloc)) -#else # define MALLOC -#endif - -#ifdef __GNUC__ -# define FORMATDEBUG(f,a,b) __attribute__ ((format (f,a,b))) +# define FORMATDEBUG(f,a,b) #else +# define __attribute__(x) /*NOTHING*/ +# define NORETURN +# define UNUSED +# define MALLOC # define FORMATDEBUG(f,a,b) #endif #define VARPROT(proto,like,form,var) proto FORMATDEBUG(like,form,var) + +// TODO: autoconf defines inline to some suitable keyword if the compiler does +// not understand inline itself. Just use inline in code? #if defined(HAS_INLINE) && !defined(NO_INLINES) # define INLINE inline /* configure made sure that 'inline' expands to the proper attribute */ @@ -234,102 +204,284 @@ extern int errno; #define MSDOS_FS #endif +/*------------------------------------------------------------------ + * Test for C99-compatible data types + * TODO: check if we can remove these checks once (if?) we require a C99 + * compliant build environment. + */ +#if defined(HAVE_INTTYPES_H) + /* C99 compliant inttypes.h. */ +# include +#endif +#if defined(HAVE_STDINT_H) + /* C99 compliant stdint.h available + * Usually it gets included also in inttypes.h, but it doesn't hurt to + * include it specifically. */ +# include +#endif + +/* If stdint.h or inttypes.h don't have int8_t, int16_t, int32_t, int64_t, + * uint8_t, uint16_t, uint32_t, uint64_t, intmax_t, uintmax_t, intptr_t, + * or uintmax_t, autoconf will have them defined to a suitable type now. + * If Autoconf did not find suitable types, there is probably no sense in + * searching them ourself. + */ +#if !defined(HAVE_INTPTR_T) && !defined(intptr_t) + /* If there is no intptr_t in stdint.h and autoconf did not find a + * suitable type, we're out of luck (because in this case we are unlikely + * to find one). */ +# error Autoconf did not find an integer type with same size as a pointer + Thats it. +#endif +#if !defined(INT32_MAX) && !defined(int32_t) +# error Autoconf did not find an integer type with exactly 32 bits. + Thats it. +#endif + +/* If mode_t, off_t, pid_t, size_t or ssize_t are not defined by the standard + * headers on this system, autoconf will have them defined as well. + */ + + +/*------------------------------------------------------------------ + * Limits for less-standard integral types: + * + * LONGLONG_MIN, LONGLONG_MAX, ULONGLONG_MAX + * TODO: Add SIZEOF_SIZET to configure, and SIZET_limits here. + * TODO:: Then use SIZET_limits in smalloc::smalloc(). + */ +#if defined(HAVE_LONG_LONG) && !defined(LONGLONG_MIN) +# if defined(LONG_LONG_MAX) +# define LONGLONG_MIN LONG_LONG_MIN +# define LONGLONG_MAX LONG_LONG_MAX +# define ULONGLONG_MAX ULONG_LONG_MAX +# elif SIZEOF_LONG_LONG == 8 +# define LONGLONG_MIN (-9223372036854775807LL - 1) +# define LONGLONG_MAX (9223372036854775807LL) +# define ULONGLONG_MAX (0xffffffffffffffffULL) +# elif SIZEOF_LONG_LONG == SIZEOF_LONG +# define LONGLONG_MIN LONG_MIN +# define LONGLONG_MAX LONG_MAX +# define ULONGLONG_MAX ULONG_MAX +# elif SIZEOF_LONG_LONG == SIZEOF_INT +# define LONGLONG_MIN INT_MIN +# define LONGLONG_MAX INT_MAX +# define ULONGLONG_MAX UINT_MAX +# endif +#endif /*------------------------------------------------------------------ * Integral types: - * Bool, SBool, CBool: boolean type, sized as int/short/char. + * Bool, SBool, CBool: boolean type, sized as _Bool or int, short, char. * p_int : an integer that has the same size as a pointer * ph_int : an integer that has half the size of a pointer * mp_int : an integer that has at least the size of a pointer * int32 : an integer with 32 bits * PTRTYPE: a type to use with constant pointer arithmetic. * The unsigned versions use 'uint' instead of 'int'. + * Additionally to the type themselves we define format specifiers for + * printing our types with sprintf() (PRN*) and scanning them with sscanf() + * (SCN*). * Changes here must be reflected in my-limits.h . - * TODO: Add a type 'u/schar', '(u/s)int8' and '(u/s)int16'., unless not already - * TODO:: defined by STDC. - * TODO: inttypes.h, stdint.h, limits.h have many interesting types... + * Additional integral types from stdint.h/inttypes.h are available (s. above) + * TODO: check, if it is feasible to use the C99 data types instead of our own + * TODO::names in the future. */ /* p_int : an integer that has the same size as a pointer */ -#define SIZEOF_PINT SIZEOF_CHAR_P - -#if SIZEOF_LONG == SIZEOF_CHAR_P - typedef long p_int; - typedef unsigned long p_uint; -# define PINT_MIN LONG_MIN -# define PINT_MAX LONG_MAX -# define PUINT_MAX ULONG_MAX - -#elif SIZEOF_INT == SIZEOF_CHAR_P - typedef int p_int; - typedef unsigned int p_uint; -# define PINT_MIN INT_MIN -# define PINT_MAX INT_MAX -# define PUINT_MAX UINT_MAX - -#elif defined(HAVE_LONG_LONG) && SIZEOF_LONG_LONG == SIZEOF_CHAR_P - typedef long long p_int; - typedef unsigned long long p_uint; -# define PINT_MIN LONGLONG_MIN -# define PINT_MAX LONGLONG_MAX -# define PUINT_MAX ULONGLONG_MAX - +#if defined(HAVE_INTPTR_T) && SIZEOF_INT != SIZEOF_CHAR_P + /* just use intptr_t + * BUT! glibc on ILP32 platforms unfortunately defines intptr_t as int, + * not as long. While this doesn't change things in principle, because they + * have equal size, gcc will output a bunch of warnings on + * sprintf("%ld",p_int) because %ld is the wrong format specifier for int. + * Therefore this little hack, which uses intptr_t for the time being + * only if sizeof(int) != sizeof(char*) (because then intptr_t cannot be + * an int). As it is not guaranteed that p_int will always be a long or + * have the size of a long, this %ld for outputting p_int are anyway a + * problem. + * TODO: As soon, as all the %ld for p_int are replaced, this hack should + * TODO::be removed! + */ + typedef intptr_t p_int; + typedef uintptr_t p_uint; +# define PINT_MIN INTPTR_MIN +# define PINT_MAX INTPTR_MAX +# define PUINT_MAX UINTPTR_MAX +# define SIZEOF_PINT SIZEOF_INTPTR_T +# define PRIdPINT PRIdPTR +# define PRIuPINT PRIuPTR +# define PRIxPINT PRIxPTR +# define SCNdPINT SCNdPTR +# define SCNuPINT SCNuPTR +# define SCNxPINT SCNxPTR +# ifdef __PRIPTR_PREFIX +# define PRI_PINT_PREFIX __PRIPTR_PREFIX +# else + /* ugly - it is a pity that the format specifiers are standardized but not + * the length modifier. But we need one for sprintf.c. *sigh* */ +# if SIZEOF_INTPTR_T == SIZEOF_LONG +# define PRI_PINT_PREFIX "l" +# elif SIZEOF_INTPTR_T == SIZEOF_INT +# define PRI_PINT_PREFIX +# elif HAVE_LONG_LONG && SIZEOF_INTPTR_T == SIZEOF_LONG_LONG +# define PRI_PINT_PREFIX "ll" +# else +# error Could not find a length modifier for intptr_t. + Thats it. +# endif +# endif #else -#error cannot find an integer type with same size as a pointer -Thats it. -#endif + /* autoconf will have some type defined to intptr_t, but it won't define the + * limits and we won't have SIZEOF_INTPTR_T available. Therefore we have to + * search ourselves the old way. + * TODO: remove once C99 support is required */ +# define SIZEOF_PINT SIZEOF_CHAR_P +# if SIZEOF_LONG == SIZEOF_CHAR_P + typedef long p_int; + typedef unsigned long p_uint; +# define PINT_MIN LONG_MIN +# define PINT_MAX LONG_MAX +# define PUINT_MAX ULONG_MAX +# define PRI_PINT_PREFIX "l" +# elif SIZEOF_INT == SIZEOF_CHAR_P + typedef int p_int; + typedef unsigned int p_uint; +# define PINT_MIN INT_MIN +# define PINT_MAX INT_MAX +# define PUINT_MAX UINT_MAX +# define PRI_PINT_PREFIX +# elif defined(HAVE_LONG_LONG) && SIZEOF_LONG_LONG == SIZEOF_CHAR_P + typedef long long p_int; + typedef unsigned long long p_uint; +# define PINT_MIN LONGLONG_MIN +# define PINT_MAX LONGLONG_MAX +# define PUINT_MAX ULONGLONG_MAX +# define PRI_PINT_PREFIX "ll" +# else + /* nearly impossible (s. intptr_t check above, but better safe than + * sorry. */ +# error cannot find an integer type with same size as a pointer + Thats it. +# endif +# define PRIdPINT PRI_PINT_PREFIX "d" +# define PRIuPINT PRI_PINT_PREFIX "u" +# define PRIxPINT PRI_PINT_PREFIX "x" +# define SCNdPINT PRI_PINT_PREFIX "d" +# define SCNuPINT PRI_PINT_PREFIX "u" +# define SCNxPINT PRI_PINT_PREFIX "x" +#endif // HAVE_INTPTR_T -/* ph_int : an integer that has half the size of a pointer */ + +/* ph_int : an integer that has half the size of a pointer. + * Unfortuntately C99 has nothing like this and therefore we have to find our + * own. + */ #if SIZEOF_CHAR_P == SIZEOF_INT * 2 typedef int ph_int; typedef unsigned int ph_uint; # define PHINT_MIN INT_MIN # define PHINT_MAX INT_MAX # define PHUINT_MAX UINT_MAX - +# define PRI_PHINT_PREFIX +#elif SIZEOF_CHAR_P == SIZEOF_SHORT * 2 + typedef short ph_int; + typedef unsigned short ph_uint; +# define PHINT_MIN SHRT_MIN +# define PHINT_MAX SHRT_MAX +# define PHUINT_MAX USHRT_MAX +# define PRI_PHINT_PREFIX "h" +#elif SIZEOF_CHAR_P == SIZEOF_LONG * 2 + typedef long ph_int; + typedef unsigned long ph_uint; +# define PHINT_MIN LONG_MIN +# define PHINT_MAX LONG_MAX +# define PHUINT_MAX ULONG_MAX +# define PRI_PHINT_PREFIX "l" #else -# if SIZEOF_CHAR_P == 4 -/* short is assumed to be always 2 bytes. */ -/* TODO: This is a dangerous assumption. */ - typedef short ph_int; - typedef unsigned short ph_uint; -# define PHINT_MIN SHORT_MIN -# define PHINT_MAX SHORT_MAX -# define PHUINT_MAX USHORT_MAX -# endif +# error Cannot find an integer of half the size of a pointer. + Thats it. #endif +#define PRIdPHINT PRI_PHINT_PREFIX "d" +#define PRIuPHINT PRI_PHINT_PREFIX "u" +#define PRIxPHINT PRI_PHINT_PREFIX "x" +#define SCNdPHINT PRI_PHINT_PREFIX "d" +#define SCNuPHINT PRI_PHINT_PREFIX "u" +#define SCNxPHINT PRI_PHINT_PREFIX "x" -/* mp_int : an integer that has at least the size of a pointer */ +/* mp_int : an integer that has at least the size of a pointer + * TODO: use intmax_t intstead once the driver does not assume mp_ints to be + * TODO::longs? */ typedef p_int mp_int; -typedef p_uint mp_uint; +typedef p_uint mp_uint; #define MPINT_MIN PINT_MIN #define MPINT_MAX PINT_MAX #define MPUINT_MAX PUINT_MAX +#define PRIdMPINT PRIdPINT +#define PRIuMPINT PRIuPINT +#define PRIxMPINT PRIxPINT +#define SCNdMPINT PRIdPINT +#define SCNuMPINT PRIuPINT +#define SCNxMPINT PRIxPINT + #ifndef __BEOS__ -/* int32 : an integer with 32 bits. */ -/* TODO: Add a configuration check for 'int32' typedef */ -# if SIZEOF_LONG == 4 -# if !defined(_AIX) -typedef long int32; -# endif -typedef unsigned long uint32; -# else -# if SIZEOF_INT == 4 -typedef int int32; -typedef unsigned int uint32; -# endif +/* int32 : an integer with 32 bits. + TODO: just use (u)int32_t instead of (u)int32. */ +typedef int32_t int32; +typedef uint32_t uint32; +# ifndef PRId32 + /* unfortunately there seems to be no PRId32 from inttypes.h or alike. + TODO: Once we require C99, we can get rid of the this stuff */ +# if !defined(CHAR_BIT) || CHAR_BIT != 8 +# error CHAR_BIT does not exist or is != 8 which is currently not supported! + Thats it. # endif + /* now sizeof(int32) has to be sizeof(char) * 4 == 4. */ +# if SIZEOF_INT == 4 +# define __PRId32PREFIX +# elif SIZEOF_LONG == 4 +# define __PRId32PREFIX "l" +# elif SIZEOF_SHORT == 4 +# define __PRIx32PREFIX "h" +# else +# error Could not find length modifier for (u)int32 + Thats it. +# endif +# define PRId32 __PRId32PREFIX "d" +# define PRIu32 __PRId32PREFIX "u" +# define PRIx32 __PRId32PREFIX "x" +# endif /* PRId32 */ #endif /* __BEOS__ */ -/* Boolean datatype and values */ -typedef int Bool; /* naming it 'bool' clashes on some machines... */ +/* type to use with constant pointer arithmetic. */ +#define PTRTYPE char * + + +/* Boolean datatype and values */ +#ifdef HAVE_STDBOOL_H +# include +#else +# ifndef HAVE__BOOL + /* _Bool is not available - typedef our own with int. + * naming it 'bool' clashes on some machines... */ + typedef int _Bool; +# endif + /* define true and false as stdbool.h does. */ +# define false 0 +# define true 1 +# define __bool_true_false_are_defined 1 +#endif // HAVE_STDBOOL_H +/* _Bool looks strange and we anyway used Bool until now. */ +typedef _Bool Bool; +/* TODO: check if these two can be merged with Bool */ typedef short SBool; typedef char CBool; -#define MY_TRUE (1) -#define MY_FALSE (0) +#define MY_TRUE (true) +#define MY_FALSE (false) + /* TODO: This should go into my-malloc.h? */ #ifdef FREE_RETURNS_VOID @@ -340,17 +492,11 @@ typedef char CBool; # define FREE_RETURN return 1; #endif -#define PTRTYPE char * - /*------------------------------------------------------------------ * Provide functions, types and defines missing from the system headers. */ -#ifndef HAVE_SSIZE_T -typedef signed long ssize_t; -#endif - #ifndef HAVE_MEMCPY /* The following 'implementation' is suitable for throwing away a value, but not to using it; the cast to return int is likely to show a warning @@ -427,7 +573,8 @@ typedef signed long ssize_t; extern char current_time_stamp[]; extern mp_int get_current_time(void); -extern char * time_string(mp_int); +extern char * time_fstring(mp_int t, const char* str, Bool localized) + FORMATDEBUG(strftime,2,0); extern char * utime_string(mp_int, mp_int); extern char * time_stamp(void); extern char *xmemmem(const char *, size_t, const char *, size_t); diff --git a/src/prolang.y b/src/prolang.y index cbda0ca..c37faa1 100644 --- a/src/prolang.y +++ b/src/prolang.y @@ -87,6 +87,7 @@ #include #include #include +#include #include "prolang.h" @@ -114,6 +115,8 @@ #include "wiz_list.h" #include "xalloc.h" +#include "i-eval_cost.h" + #include "../mudlib/sys/driver_hook.h" #ifdef USE_NEW_INLINES @@ -574,6 +577,10 @@ struct block_scope_s { int first_local; /* Number of first local defined in this scope */ int num_locals; /* Number of locals defined in this scope */ + int num_cleared; + /* Number of locals that have been cleared by earlier CLEAR_LOCALS */ + Bool clobbered; + /* Local variables beyond num_locals may be clobbered */ mp_uint addr; /* Address of CLEAR_LOCALS instruction, needed for backpatching */ }; @@ -1185,8 +1192,8 @@ add_string_constant (void) tmp = mstr_add(last_string_constant, last_lex_string); if (!tmp) { - yyerrorf("Out of memory for string literal (%ld bytes)" - , (long)(mstrsize(last_string_constant) + yyerrorf("Out of memory for string literal (%zu bytes)" + , (mstrsize(last_string_constant) +mstrsize(last_lex_string)) ); return; @@ -1196,7 +1203,8 @@ add_string_constant (void) last_string_constant = make_tabled(tmp); if (!last_string_constant) { - yyerror("Out of memory for string literal (%ld bytes)"); + yyerrorf("Out of memory for string literal (%zu bytes)", + mstrsize(tmp)); } } /* add_string_constant() */ @@ -1518,8 +1526,8 @@ get_type_name (fulltype_t type) } if (type.typeflags >= sizeof type_name / sizeof type_name[0]) - fatal("Bad type %ld: %s line %d\n" - , (long)type.typeflags, current_loc.file->name, current_loc.line); + fatal("Bad type %"PRIu32": %s line %d\n" + , type.typeflags, current_loc.file->name, current_loc.line); strcat(buff, type_name[type.typeflags]); @@ -1879,7 +1887,7 @@ ins_byte (unsigned char b) { if (!realloc_a_program(1)) { - yyerrorf("Out of memory: program size %lu\n" + yyerrorf("Out of memory: program size %"PRIuMPINT"\n" , mem_block[A_PROGRAM].current_size + 1); return; } @@ -1929,7 +1937,7 @@ ins_short (long l) } else { - yyerrorf("Out of memory: program size %lu\n" + yyerrorf("Out of memory: program size %"PRIuMPINT"\n" , mem_block[A_PROGRAM].current_size + 2); } } /* ins_short() */ @@ -1991,7 +1999,7 @@ ins_int32 (int32 l) /* Add the 4-byte number to the A_PROGRAM area in a fixed byteorder. */ - +/* TODO: check callers for assumptions that a long is always 4 bytes. */ { if (realloc_a_program(4)) { @@ -2005,7 +2013,7 @@ ins_int32 (int32 l) } else { - yyerrorf("Out of memory: program size %lu\n" + yyerrorf("Out of memory: program size %"PRIuMPINT"\n" , mem_block[A_PROGRAM].current_size + 4); } } /* ins_int32() */ @@ -2017,6 +2025,7 @@ upd_int32 (mp_uint offset, int32 l) /* Store the 4-byte number at in the A_PROGRAM are in * a fixed byteorder. */ +/* TODO: check callers for assumptions that a long is always 4 bytes. */ { char *dest; @@ -2031,9 +2040,10 @@ read_int32 (mp_uint offset) /* Return the 4-byte number stored at in the A_PROGRAM area. */ +/* TODO: this should probably read in a int32. */ { - int32 l; + long l; char *dest; dest = mem_block[A_PROGRAM].block + offset; @@ -2236,8 +2246,8 @@ fix_branch (int ltoken, p_int dest, p_int loc) upd_short(loc, offset+2); if (offset > 0x7ffd) - yyerrorf("Compiler limit: Too much code to branch over: %ld bytes" - , offset); + yyerrorf("Compiler limit: Too much code to branch over: %" + PRIdPINT" bytes", offset); return MY_TRUE; } @@ -2263,7 +2273,7 @@ yyget_space (p_int size) CURRENT_PROGRAM_SIZE += size; return PROGRAM_BLOCK + CURRENT_PROGRAM_SIZE - size; } - yyerrorf("Out of memory: program size %lu\n" + yyerrorf("Out of memory: program size %"PRIdMPINT"\n" , mem_block[A_PROGRAM].current_size + size); return NULL; } /* yyget_space() */ @@ -2305,7 +2315,7 @@ yymove_switch_instructions (int len, p_int blocklen) } else { - yyerrorf("Out of memory: program size %lu\n" + yyerrorf("Out of memory: program size %"PRIdMPINT"\n" , mem_block[A_PROGRAM].current_size + len); } } /* yymove_switch_instructions() */ @@ -2374,7 +2384,7 @@ update_lop_branch ( p_uint address, int instruction ) upd_short(address+1, offset+3); if (offset > 0x7ffc) yyerrorf("Compiler limit: Too much code to skip for ||/&&:" - " %ld bytes" , offset); + " %"PRIdPINT" bytes" , offset); p[0] = F_POP_VALUE; } else @@ -2522,7 +2532,10 @@ add_local_name (ident_t *ident, fulltype_t type, int depth */ #ifdef USE_NEW_INLINES #ifdef DEBUG_INLINES -if (current_inline && current_inline->block_depth+2 == block_depth && ident->type != I_TYPE_GLOBAL) printf("DEBUG: redeclare local '%s' as inline arg, depth %d\n", get_txt(ident->name), block_depth); +if (current_inline && current_inline->block_depth+2 == block_depth + && ident->type != I_TYPE_GLOBAL) + printf("DEBUG: redeclare local '%s' as inline arg, depth %d\n", + get_txt(ident->name), block_depth); #endif /* DEBUG_INLINES */ if (ident->type != I_TYPE_GLOBAL && !(current_inline && current_inline->block_depth+2 == block_depth) @@ -2632,7 +2645,8 @@ add_context_name (ident_t *ident, fulltype_t type, int num) block = & block_scope[depth-1]; #ifdef DEBUG_INLINES -printf("DEBUG: add_context_name('%s', num %d) depth %d, context %d\n", get_txt(ident->name), num, depth, block->num_locals); +printf("DEBUG: add_context_name('%s', num %d) depth %d, context %d\n", + get_txt(ident->name), num, depth, block->num_locals); #endif /* DEBUG_INLINES */ if (block->num_locals >= 256 || block->num_locals >= MAX_LOCAL /* size of type recording array */ @@ -2770,6 +2784,8 @@ init_scope (int depth) { block_scope[depth-1].num_locals = 0; block_scope[depth-1].first_local = current_number_of_locals; + block_scope[depth-1].num_cleared = 0; + block_scope[depth-1].clobbered = MY_FALSE; block_scope[depth-1].addr = 0; } /* init_scope() */ @@ -2793,10 +2809,13 @@ enter_block_scope (void) /*-------------------------------------------------------------------------*/ static void -leave_block_scope (void) +leave_block_scope (Bool dontclobber) /* Leave the current scope (if use_local_scopes requires it), freeing * all local names defined in that scope. + * + * should be MY_TRUE if the stack of the to-be-left scope + * is independent of the outer scope (i.e. the scope of closures). */ { @@ -2804,6 +2823,13 @@ leave_block_scope (void) { free_local_names(block_depth); block_depth--; + if (block_depth && !dontclobber + && (block_scope[block_depth].num_locals + || block_scope[block_depth].clobbered)) + { + /* the block we just left may have clobbered local variables */ + block_scope[block_depth-1].clobbered = MY_TRUE; + } } } /* leave_block_scope() */ @@ -4118,6 +4144,11 @@ find_struct ( string_t * name ) ident_t * p; p = find_shared_identifier(get_txt(name), I_TYPE_GLOBAL, 0); + + /* Find the global struct identifier */ + while (p != NULL && p->type != I_TYPE_GLOBAL) + p = p->inferior; + if (p == NULL || p->u.global.struct_id < 0) return -1; if (STRUCT_DEF(p->u.global.struct_id).flags & NAME_HIDDEN) @@ -4727,7 +4758,7 @@ new_inline_closure (void) ict.prev = current_inline - &(INLINE_CLOSURE(0)); } #ifdef DEBUG_INLINES -printf("DEBUG: new inline #%d: prev %d\n", INLINE_CLOSURE_COUNT, ict.prev); +printf("DEBUG: new inline #%"PRIuMPINT": prev %"PRIdMPINT"\n", INLINE_CLOSURE_COUNT, ict.prev); #endif /* DEBUG_INLINES */ /* Initialize the other fields */ @@ -4748,7 +4779,9 @@ printf("DEBUG: new inline #%d: prev %d\n", INLINE_CLOSURE_COUNT, ict.prev); ict.end_line = stored_lines; #ifdef DEBUG_INLINES -printf("DEBUG: start: %ld, depth %d, locals: %d/%d, break: %d/%d\n", CURRENT_PROGRAM_SIZE, block_depth, current_number_of_locals, max_number_of_locals, current_break_stack_need, max_break_stack_need); +printf("DEBUG: start: %"PRIuMPINT", depth %d, locals: %d/%d, break: %d/%d\n", + CURRENT_PROGRAM_SIZE, block_depth, current_number_of_locals, + max_number_of_locals, current_break_stack_need, max_break_stack_need); #endif /* DEBUG_INLINES */ ict.block_depth = block_depth; ict.break_stack_size = current_break_stack_need; @@ -4761,7 +4794,8 @@ printf("DEBUG: start: %ld, depth %d, locals: %d/%d, break: %d/%d\n", CURRENT_P ict.full_context_type_start = type_of_context - &(LOCAL_TYPE(0)); ict.full_local_type_size = mem_block[A_LOCAL_TYPES].current_size; #ifdef DEBUG_INLINES -printf("DEBUG: local types: %d, context types: %d\n", ict.full_local_type_start, ict.full_context_type_start); +printf("DEBUG: local types: %"PRIuMPINT", context types: %"PRIuMPINT"\n", + ict.full_local_type_start, ict.full_context_type_start); #endif /* DEBUG_INLINES */ /* Extend the type memblocks */ @@ -4775,7 +4809,8 @@ printf("DEBUG: local types: %d, context types: %d\n", ict.full_local_type_star type_of_context = &(LOCAL_TYPE(type_count)); type_of_locals = &(LOCAL_TYPE(type_count+MAX_LOCAL)); #ifdef DEBUG_INLINES -printf("DEBUG: type ptrs: %p, %p\n", type_of_locals, type_of_context ); +printf("DEBUG: type ptrs: %p, %p\n", + type_of_locals, type_of_context ); #endif /* DEBUG_INLINES */ } @@ -4807,8 +4842,15 @@ finish_inline_closure (Bool bAbort) #ifdef DEBUG_INLINES { mp_int index = current_inline - &(INLINE_CLOSURE(0)); -printf("DEBUG: %s inline #%d: prev %d, end %ld, start %ld, length %ld, function %d pc %ld\n", bAbort ? "abort" : "finish", index, current_inline->prev, current_inline->end, current_inline->start, current_inline->length, current_inline->function, FUNCTION(current_inline->function)->offset.pc); -printf("DEBUG: depth %d, locals: %d/%d, break: %d/%d\n", current_inline->block_depth, current_inline->num_locals, current_inline->max_num_locals, current_inline->break_stack_size, current_inline->max_break_stack_size); +printf("DEBUG: %s inline #%"PRIdMPINT": prev %"PRIdMPINT", end %"PRIuMPINT + ", start %"PRIuMPINT", length %"PRIuMPINT", function %d pc %"PRIu32"\n", + bAbort ? "abort" : "finish", index, current_inline->prev, + current_inline->end, current_inline->start, current_inline->length, + current_inline->function, FUNCTION(current_inline->function)->offset.pc); +printf("DEBUG: depth %d, locals: %d/%d, break: %d/%d\n", + current_inline->block_depth, current_inline->num_locals, + current_inline->max_num_locals, current_inline->break_stack_size, + current_inline->max_break_stack_size); } #endif /* DEBUG_INLINES */ @@ -4821,7 +4863,7 @@ printf("DEBUG: depth %d, locals: %d/%d, break: %d/%d\n", current_inline->block { backup_start = INLINE_PROGRAM_SIZE; #ifdef DEBUG_INLINES -printf("DEBUG: move code to backup %ld\n", backup_start); +printf("DEBUG: move code to backup %"PRIuMPINT"\n", backup_start); #endif /* DEBUG_INLINES */ add_to_mem_block( A_INLINE_PROGRAM, PROGRAM_BLOCK+start, length); current_inline->start = backup_start; @@ -4834,7 +4876,9 @@ printf("DEBUG: move code to backup %ld\n", backup_start); if (start + length < CURRENT_PROGRAM_SIZE) { #ifdef DEBUG_INLINES -printf("DEBUG: move code forward: from %ld, length %ld, to %ld\n", start+length, CURRENT_PROGRAM_SIZE - length - start, end); +printf("DEBUG: move code forward: from %"PRIuMPINT", length %"PRIuMPINT + ", to %"PRIuMPINT"\n", + start+length, CURRENT_PROGRAM_SIZE - length - start, end); #endif /* DEBUG_INLINES */ memmove( PROGRAM_BLOCK+end , PROGRAM_BLOCK+start+length @@ -4845,7 +4889,7 @@ printf("DEBUG: move code forward: from %ld, length %ld, to %ld\n", start+lengt stored_bytes -= length + (start - end); #ifdef DEBUG_INLINES -printf("DEBUG: program size: %ld\n", CURRENT_PROGRAM_SIZE); +printf("DEBUG: program size: %"PRIuMPINT"\n", CURRENT_PROGRAM_SIZE); #endif /* DEBUG_INLINES */ /* Move the linenumber data into the backup storage */ @@ -4855,7 +4899,9 @@ printf("DEBUG: program size: %ld\n", CURRENT_PROGRAM_SIZE); { backup_start = INLINE_PROGRAM_SIZE; #ifdef DEBUG_INLINES -printf("DEBUG: move li data to %ld, from %ld length %ld\n", backup_start, start, length); +printf("DEBUG: move li data to %"PRIuMPINT", from %"PRIuMPINT" length %" + PRIuMPINT"\n", + backup_start, start, length); #endif /* DEBUG_INLINES */ add_to_mem_block( A_INLINE_PROGRAM, LINENUMBER_BLOCK+start, length); current_inline->li_start = backup_start; @@ -4878,7 +4924,9 @@ printf("DEBUG: move li data to %ld, from %ld length %ld\n", backup_start, star if (start + length < LINENUMBER_SIZE) { #ifdef DEBUG_INLINES -printf("DEBUG: move li data forward: from %ld, length %ld, to %ld\n", start+length, LINENUMBER_SIZE - length - start, start); +printf("DEBUG: move li data forward: from %"PRIuMPINT", length %"PRIuMPINT + ", to %"PRIuMPINT"\n", + start+length, LINENUMBER_SIZE - length - start, start); #endif /* DEBUG_INLINES */ memmove( LINENUMBER_BLOCK+start , LINENUMBER_BLOCK+start+length @@ -4898,7 +4946,8 @@ printf("DEBUG: move li data forward: from %ld, length %ld, to %ld\n", start+le exact_types = current_inline->exact_types; #ifdef DEBUG_INLINES -printf("DEBUG: local types: %d, context types: %d\n", current_inline->full_local_type_start, current_inline->full_context_type_start); +printf("DEBUG: local types: %"PRIuMPINT", context types: %"PRIuMPINT"\n", + current_inline->full_local_type_start, current_inline->full_context_type_start); #endif /* DEBUG_INLINES */ type_of_locals = &(LOCAL_TYPE(current_inline->full_local_type_start)); type_of_context = &(LOCAL_TYPE(current_inline->full_context_type_start)); @@ -4936,14 +4985,18 @@ insert_pending_inline_closures (void) { mp_int ix; #ifdef DEBUG_INLINES -if (INLINE_CLOSURE_COUNT != 0) printf("DEBUG: insert_inline_closures(): %d pending\n", INLINE_CLOSURE_COUNT); +if (INLINE_CLOSURE_COUNT != 0) printf("DEBUG: insert_inline_closures(): %" + PRIuMPINT" pending\n", + INLINE_CLOSURE_COUNT); #endif /* DEBUG_INLINES */ for (ix = 0; (size_t)ix < INLINE_CLOSURE_COUNT; ix++) { inline_closure_t * ict = &(INLINE_CLOSURE(ix)); #ifdef DEBUG_INLINES -printf("DEBUG: #%d: start %ld, length %ld, function %d: new start %ld\n", ix, ict->start, ict->length, ict->function, CURRENT_PROGRAM_SIZE); +printf("DEBUG: #%"PRIdMPINT": start %"PRIuMPINT", length %"PRIuMPINT + ", function %d: new start %"PRIuMPINT"\n", + ix, ict->start, ict->length, ict->function, CURRENT_PROGRAM_SIZE); #endif /* DEBUG_INLINES */ if (ict->length != 0) { @@ -4952,12 +5005,25 @@ printf("DEBUG: #%d: start %ld, length %ld, function %d: new start %ld\n", ix, store_line_number_info(); if (stored_lines > ict->start_line) store_line_number_backward(stored_lines - ict->start_line); + else + while (stored_lines < ict->start_line) + { + int lines; + + lines = ict->start_line - stored_lines; + if (lines > LI_MAXEMPTY) + lines = LI_MAXEMPTY; + stored_lines += lines; + byte_to_mem_block(A_LINENUMBERS, 256 - lines); + } FUNCTION(ict->function)->offset.pc = CURRENT_PROGRAM_SIZE + FUNCTION_PRE_HDR_SIZE; add_to_mem_block(A_PROGRAM, INLINE_PROGRAM_BLOCK(ict->start) , ict->length); #ifdef DEBUG_INLINES -printf("DEBUG: li_start %ld, li_length %ld, new li_start %ld\n", ict->li_start, ict->li_length, LINENUMBER_SIZE); +printf("DEBUG: li_start %"PRIuMPINT", li_length %"PRIuMPINT + ", new li_start %"PRIuMPINT"\n", + ict->li_start, ict->li_length, LINENUMBER_SIZE); #endif /* DEBUG_INLINES */ add_to_mem_block(A_LINENUMBERS, INLINE_PROGRAM_BLOCK(ict->li_start) @@ -5019,6 +5085,12 @@ prepare_inline_closure (fulltype_t returntype) ident = make_shared_identifier(name, I_TYPE_UNKNOWN, 0); + /* The lfuns implementing the inline closures should not + * be callable directly (without the CLOSURE svalue), and also not + * overrideable. + */ + returntype.typeflags |= TYPE_MOD_NO_MASK | TYPE_MOD_PRIVATE; + def_function_typecheck(returntype, ident, MY_TRUE); #ifdef DEBUG_INLINES printf("DEBUG: New inline closure name: '%s'\n", name); @@ -5069,7 +5141,8 @@ printf("DEBUG: Function index: %d\n", current_inline->function); */ current_inline->end = CURRENT_PROGRAM_SIZE; #ifdef DEBUG_INLINES -printf("DEBUG: program size: %ld align to %ld\n", CURRENT_PROGRAM_SIZE, align(CURRENT_PROGRAM_SIZE)); +printf("DEBUG: program size: %"PRIuMPINT" align to %"PRIuMPINT"\n", + CURRENT_PROGRAM_SIZE, align(CURRENT_PROGRAM_SIZE)); #endif /* DEBUG_INLINES */ CURRENT_PROGRAM_SIZE = align(CURRENT_PROGRAM_SIZE); current_inline->start = CURRENT_PROGRAM_SIZE; @@ -5083,7 +5156,7 @@ printf("DEBUG: program size: %ld align to %ld\n", CURRENT_PROGRAM_SIZE, align( } else { - yyerrorf("Out of memory: program size %lu\n" + yyerrorf("Out of memory: program size %"PRIuMPINT"\n" , mem_block[A_PROGRAM].current_size + FUNCTION_HDR_SIZE); finish_inline_closure(MY_TRUE); return MY_FALSE; @@ -5118,8 +5191,8 @@ printf("DEBUG: Generate inline closure function:\n"); yyerror("Implementation restriction: Inline closure must not span " "include file limits"); /* Clean up */ - leave_block_scope(); /* Argument scope */ - leave_block_scope(); /* Context scope */ + leave_block_scope(MY_TRUE); /* Argument scope */ + leave_block_scope(MY_TRUE); /* Context scope */ finish_inline_closure(MY_TRUE); return; } @@ -5177,7 +5250,8 @@ printf("DEBUG: %d context vars, depth %d\n", context->num_locals, depth); ; id = id->next_all) { #ifdef DEBUG_INLINES -if (id->u.local.depth == depth) printf("DEBUG: '%s': local %d, context %d\n", get_txt(id->name), id->u.local.num, id->u.local.context); +if (id->u.local.depth == depth) printf("DEBUG: '%s': local %d, context %d\n", + get_txt(id->name), id->u.local.num, id->u.local.context); #endif /* DEBUG_INLINES */ if (id->u.local.depth == depth && id->u.local.context >= 0 @@ -5224,8 +5298,8 @@ printf("DEBUG: -> F_CONTEXT_CLOSURE %d %d\n", current_inline->function, cont /* Clean up */ - leave_block_scope(); /* Argument scope */ - leave_block_scope(); /* Context scope */ + leave_block_scope(MY_TRUE); /* Argument scope */ + leave_block_scope(MY_TRUE); /* Context scope */ finish_inline_closure(MY_FALSE); } /* complete_inline_closure() */ #endif /* USE_NEW_INLINES */ @@ -5858,7 +5932,7 @@ function_body: } else { - yyerrorf("Out of memory: program size %lu\n" + yyerrorf("Out of memory: program size %"PRIuMPINT"\n" , mem_block[A_PROGRAM].current_size + FUNCTION_HDR_SIZE); YYACCEPT; } @@ -5881,7 +5955,7 @@ inline_func: { #ifdef DEBUG_INLINES -printf("DEBUG: After inline_opt_type: program size %ld\n", CURRENT_PROGRAM_SIZE); +printf("DEBUG: After inline_opt_type: program size %"PRIuMPINT"\n", CURRENT_PROGRAM_SIZE); #endif /* DEBUG_INLINES */ if (!prepare_inline_closure($2)) YYACCEPT; @@ -5891,7 +5965,7 @@ printf("DEBUG: After inline_opt_type: program size %ld\n", CURRENT_PROGRAM_SIZE) { #ifdef DEBUG_INLINES -printf("DEBUG: After inline_opt_args: program size %ld\n", CURRENT_PROGRAM_SIZE); +printf("DEBUG: After inline_opt_args: program size %"PRIuMPINT"\n", CURRENT_PROGRAM_SIZE); #endif /* DEBUG_INLINES */ current_inline->parse_context = MY_TRUE; } @@ -5900,7 +5974,7 @@ printf("DEBUG: After inline_opt_args: program size %ld\n", CURRENT_PROGRAM_SIZE) { #ifdef DEBUG_INLINES -printf("DEBUG: After inline_opt_context: program size %ld\n", CURRENT_PROGRAM_SIZE); +printf("DEBUG: After inline_opt_context: program size %"PRIuMPINT"\n", CURRENT_PROGRAM_SIZE); #endif /* DEBUG_INLINES */ current_inline->parse_context = MY_FALSE; if (!inline_closure_prototype($4)) @@ -5911,7 +5985,7 @@ printf("DEBUG: After inline_opt_context: program size %ld\n", CURRENT_PROGRAM_SI { #ifdef DEBUG_INLINES -printf("DEBUG: After inline block: program size %ld\n", CURRENT_PROGRAM_SIZE); +printf("DEBUG: After inline block: program size %"PRIuMPINT"\n", CURRENT_PROGRAM_SIZE); #endif /* DEBUG_INLINES */ $$.start = current_inline->end; $$.code = -1; @@ -5927,7 +6001,7 @@ printf("DEBUG: After inline block: program size %ld\n", CURRENT_PROGRAM_SIZE); int i; #ifdef DEBUG_INLINES -printf("DEBUG: After L_BEGIN_INLINE: program size %ld\n", CURRENT_PROGRAM_SIZE); +printf("DEBUG: After L_BEGIN_INLINE: program size %"PRIuMPINT"\n", CURRENT_PROGRAM_SIZE); #endif /* DEBUG_INLINES */ if (!prepare_inline_closure(Type_Any)) YYACCEPT; @@ -5945,8 +6019,14 @@ printf("DEBUG: After L_BEGIN_INLINE: program size %ld\n", CURRENT_PROGRAM_SIZE); if (!inline_closure_prototype(9)) YYACCEPT; + + /* Put the code block in its own scope apart from the + * parameters, so that define_local_variable doesn't + * assume that there are already 9 Variables. + */ + enter_block_scope(); #ifdef DEBUG_INLINES -printf("DEBUG: Before comma_expr: program size %ld\n", CURRENT_PROGRAM_SIZE); +printf("DEBUG: Before comma_expr: program size %"PRIuMPINT"\n", CURRENT_PROGRAM_SIZE); #endif /* DEBUG_INLINES */ } @@ -5956,8 +6036,20 @@ printf("DEBUG: Before comma_expr: program size %ld\n", CURRENT_PROGRAM_SIZE); { #ifdef DEBUG_INLINES -printf("DEBUG: After L_END_INLINE: program size %ld\n", CURRENT_PROGRAM_SIZE); +printf("DEBUG: After L_END_INLINE: program size %"PRIuMPINT"\n", CURRENT_PROGRAM_SIZE); #endif /* DEBUG_INLINES */ + + /* Complete the F_CLEAR_LOCALS at the baginning of the block. */ + block_scope_t *scope = block_scope + block_depth - 1; + + if (use_local_scopes && scope->num_locals > scope->num_cleared) + { + mem_block[A_PROGRAM].block[scope->addr+2] + = (char)(scope->num_locals - scope->num_cleared); + } + + leave_block_scope(MY_FALSE); + $$.start = current_inline->end; $$.code = -1; $$.type = Type_Closure; @@ -6085,7 +6177,6 @@ opt_base_struct: { /* Identifier -> no such struct encountered yet */ yyerrorf("Unknown base struct '%s'", get_txt($2->name)); - free_shared_identifier($2); } else { @@ -6155,8 +6246,6 @@ member_name_list: assign_full_to_vartype(&type, actual_type); add_struct_member($3->name, type, NULL); - if ($3->type == I_TYPE_UNKNOWN) - free_shared_identifier($3); $$ = $1; } @@ -6169,8 +6258,6 @@ member_name_list: assign_full_to_vartype(&type, actual_type); add_struct_member($4->name, type, NULL); - if ($4->type == I_TYPE_UNKNOWN) - free_shared_identifier($4); $$ = $1; } @@ -6535,10 +6622,6 @@ inheritance_qualifier: , get_txt(last_identifier->name)); $$[0] = $$[1] = 0; } - - /* Free the identifier again if this statement generated it */ - if (last_identifier->type == I_TYPE_UNKNOWN) - free_shared_identifier(last_identifier); } ; /* inheritance_qualifier */ @@ -6692,8 +6775,6 @@ identifier: /* Extract the string from the ident structure */ p = ref_mstring($1->name); - if ($1->type == I_TYPE_UNKNOWN) - free_shared_identifier($1); $$ = p; } @@ -6832,8 +6913,10 @@ name_list: /* Blocks and simple statements. */ -block: - '{' +block: '{' statements_block '}' + + +statements_block: { enter_block_scope(); } @@ -6849,18 +6932,16 @@ block: { block_scope_t *scope = block_scope + block_depth - 1; - if (use_local_scopes && scope->num_locals) + if (use_local_scopes && scope->num_locals > scope->num_cleared) { mem_block[A_PROGRAM].block[scope->addr+2] - = (char)scope->num_locals; + = (char)(scope->num_locals - scope->num_cleared); } } + + leave_block_scope(MY_FALSE); } - - '}' - - { leave_block_scope(); } -; /* block */ +; /* block_statements */ statements: @@ -6956,7 +7037,7 @@ statement: } | error ';' /* Synchronisation point */ - | cond | while | do | for | foreach | switch | case | default + | cond | while | do | for | foreach | switch | return ';' | block | /* empty */ ';' @@ -6982,7 +7063,7 @@ statement: ins_int32(current_break_address & BREAK_ADDRESS_MASK); current_break_address = CURRENT_PROGRAM_SIZE - 4; if (current_break_address > BREAK_ADDRESS_MASK) - yyerrorf("Compiler limit: (L_BREAK) value too large: %ld" + yyerrorf("Compiler limit: (L_BREAK) value too large: %"PRIdPINT , current_break_address); } } @@ -7297,7 +7378,7 @@ do: current = CURRENT_PROGRAM_SIZE; if (!realloc_a_program(3)) { - yyerrorf("Out of memory: program size %lu\n", current+3); + yyerrorf("Out of memory: program size %"PRIuMPINT"\n", current+3); YYACCEPT; } @@ -7480,10 +7561,10 @@ for: { block_scope_t *scope = block_scope + block_depth - 1; - if (use_local_scopes && scope->num_locals) + if (use_local_scopes && scope->num_locals > scope->num_cleared) { mem_block[A_PROGRAM].block[scope->addr+2] - = (char)scope->num_locals; + = (char)(scope->num_locals - scope->num_cleared); } } } @@ -7572,7 +7653,7 @@ for: current_break_address = $3[1]; /* and leave the for scope */ - leave_block_scope(); + leave_block_scope(MY_FALSE); } ; /* for */ @@ -7714,10 +7795,10 @@ foreach: { block_scope_t *scope = block_scope + block_depth - 1; - if (use_local_scopes && scope->num_locals) + if (use_local_scopes && scope->num_locals > scope->num_cleared) { mem_block[A_PROGRAM].block[scope->addr+2] - = (char)scope->num_locals; + = (char)(scope->num_locals - scope->num_cleared); } } @@ -7831,7 +7912,7 @@ foreach: current_break_address = $3[1]; /* and leave the scope */ - leave_block_scope(); + leave_block_scope(MY_FALSE); } ; /* foreach */ @@ -7957,23 +8038,20 @@ foreach_expr: * * Note that the actual switch rule is: * - * switch: L_SWITCH ( comma_expr ) block + * switch: L_SWITCH ( comma_expr ) '{' switch_block '}' * - * and that case and default are both just special kinds of statement - * which mark addresses within the statement code to which the - * switch statement may jump. + * and that case and default are explicitly parsed in the + * switch_block rule. Each group of statements after a + * label have their own scope, so that variable declarations + * within the switch block may not cross case labels. * * That also means that in contrast to C the code * * switch(x); * or switch(x) write("Foo"); + * or switch(x) {{ case "foo": break; }} * * is syntactically not ok. - * - * TODO: Since current_break_address is used to indicate an active switch(), - * TODO:: the compiler can't compile Duff's device: the inner while() hides - * TODO:: active switch(). If that is fixed, we can change the 'block' - * TODO:: back to 'statement' in the grammar rule. */ switch: @@ -7993,8 +8071,8 @@ switch: /* Save the previous switch state */ if ( !(statep = yalloc(sizeof(case_state_t))) ) { - yyerrorf("Out of memory: case state (%lu bytes)" - , (unsigned long) sizeof(case_state_t)); + yyerrorf("Out of memory: case state (%zu bytes)" + , sizeof(case_state_t)); YYACCEPT; } *statep = case_state; @@ -8019,8 +8097,12 @@ switch: if (current_continue_address) current_continue_address += SWITCH_DEPTH_UNIT; } + + '{' - block + switch_block + + '}' { %line @@ -8063,6 +8145,19 @@ switch: } ; /* switch */ + +switch_block: + switch_block switch_statements + | switch_statements +; /* switch_block */ + + +switch_statements: switch_label statements_block ; + + +switch_label: case | default ; + + case: L_CASE case_label ':' { %line @@ -8071,11 +8166,8 @@ case: L_CASE case_label ':' */ case_list_entry_t *temp; - if ( !( current_break_address & CASE_LABELS_ENABLED ) ) - { - yyerror("Case outside switch"); - break; - } + /* Should be within a switch statement. */ + assert(current_break_address & CASE_LABELS_ENABLED); /* Get and fill in a new case entry structure */ if ( !(temp = new_case_entry()) ) @@ -8104,11 +8196,8 @@ case: L_CASE case_label ':' if ( !$2.numeric || !$4.numeric ) yyerror("String case labels not allowed as range bounds"); - if ( !( current_break_address & CASE_LABELS_ENABLED ) ) - { - yyerror("Case range outside switch"); - break; - } + /* Should be within a switch statement. */ + assert(current_break_address & CASE_LABELS_ENABLED); /* A range like "case 4..2" is illegal, * a range like "case 4..4" counts as simple "case 4". @@ -8188,10 +8277,8 @@ default: * for the current switch. */ - if ( !( current_break_address & CASE_LABELS_ENABLED ) ) { - yyerror("Default outside switch"); - break; - } + /* Should be within a switch statement. */ + assert(current_break_address & CASE_LABELS_ENABLED); if (case_state.default_addr) yyerror("Duplicate default"); @@ -8232,7 +8319,7 @@ condStart: current = CURRENT_PROGRAM_SIZE; if (!realloc_a_program(2)) { - yyerrorf("Out of memory: program size %lu\n", current+3); + yyerrorf("Out of memory: program size %"PRIuMPINT"\n", current+3); YYACCEPT; } current_code = PROGRAM_BLOCK + current; @@ -9138,8 +9225,8 @@ expr0: sum = mstr_add(str1, str2); if (!sum) { - yyerrorf("Out of memory for string literal (%ld bytes)" - , (unsigned long)(mstrsize(str1)+mstrsize(str2)) + yyerrorf("Out of memory for string literal (%zu bytes)" + , (mstrsize(str1)+mstrsize(str2)) ); YYACCEPT; } @@ -9677,7 +9764,7 @@ expr0: length = $2.end - start + 1; if (!realloc_a_program(length)) { - yyerrorf("Out of memory: program size %lu\n" + yyerrorf("Out of memory: program size %"PRIuMPINT"\n" , current+length); YYACCEPT; } @@ -9706,7 +9793,8 @@ expr0: if (!realloc_a_program(3)) { - yyerrorf("Out of memory: program size %lu\n", current+3); + yyerrorf("Out of memory: program size %"PRIuMPINT"\n", + current+3); YYACCEPT; } p = PROGRAM_BLOCK + start; @@ -9728,7 +9816,8 @@ expr0: { if (!realloc_a_program(2)) { - yyerrorf("Out of memory: program size %lu\n", current+2); + yyerrorf("Out of memory: program size %"PRIuMPINT"\n", + current+2); YYACCEPT; } p = PROGRAM_BLOCK + start; @@ -9784,7 +9873,8 @@ expr0: current = CURRENT_PROGRAM_SIZE; if (!realloc_a_program(2)) { - yyerrorf("Out of memory: program size %lu\n", current+2); + yyerrorf("Out of memory: program size %"PRIuMPINT"\n", + current+2); YYACCEPT; } p = PROGRAM_BLOCK + current; @@ -10509,7 +10599,7 @@ expr4: if (!realloc_a_program(3)) { - yyerrorf("Out of memory: program size %lu\n", current+3); + yyerrorf("Out of memory: program size %"PRIuMPINT"\n", current+3); YYACCEPT; } p = PROGRAM_BLOCK + current; @@ -10563,7 +10653,8 @@ expr4: $$.code = -1; if (!realloc_a_program(2)) { - yyerrorf("Out of memory: program size %lu\n", current+2); + yyerrorf("Out of memory: program size %"PRIuMPINT"\n", + current+2); YYACCEPT; } p = PROGRAM_BLOCK + current; @@ -10761,7 +10852,7 @@ expr4: if (!realloc_a_program(3)) { - yyerrorf("Out of memory: program size %lu\n", current+3); + yyerrorf("Out of memory: program size %"PRIuMPINT"\n", current+3); YYACCEPT; } p = PROGRAM_BLOCK + current; @@ -10818,7 +10909,7 @@ expr4: $$.end = 0; if (!realloc_a_program(2)) { - yyerrorf("Out of memory: program size %lu\n", current+2); + yyerrorf("Out of memory: program size %"PRIuMPINT"\n", current+2); YYACCEPT; } p = PROGRAM_BLOCK + current; @@ -11525,7 +11616,7 @@ index_range : if (!realloc_a_program(1)) { - yyerrorf("Out of memory: program size %lu\n", current+1); + yyerrorf("Out of memory: program size %"PRIdPINT"\n", current+1); YYACCEPT; } @@ -11568,7 +11659,7 @@ index_range : if (!realloc_a_program(1)) { - yyerrorf("Out of memory: program size %lu\n", current+1); + yyerrorf("Out of memory: program size %"PRIdPINT"\n", current+1); YYACCEPT; } @@ -11611,7 +11702,7 @@ index_range : if (!realloc_a_program(1)) { - yyerrorf("Out of memory: program size %lu\n", current+1); + yyerrorf("Out of memory: program size %"PRIdPINT"\n", current+1); YYACCEPT; } @@ -12141,8 +12232,10 @@ function_call: /* It's a real simul-efun */ $$.simul_efun = real_name->u.global.sim_efun; - - if (real_name->u.global.sim_efun >= SEFUN_TABLE_SIZE) + /* real_name->u.global.sim_efun is >=0 (see above), so it can + * be casted to unsigned long before comparison (SEFUN_TABLE_SIZE + * is unsigned long) */ + if ((unsigned long)real_name->u.global.sim_efun >= SEFUN_TABLE_SIZE) { /* The simul-efun has to be called by name: * prepare the extra args for the call_other @@ -12234,7 +12327,8 @@ function_call: || has_ellipsis) ap_needed = MY_TRUE; - if (simul_efun >= SEFUN_TABLE_SIZE) + /* simul_efun is >= 0, see above) */ + if ((unsigned long)simul_efun >= SEFUN_TABLE_SIZE) { /* call-other: the number of arguments will be * corrected at runtime. @@ -12285,11 +12379,6 @@ function_call: , $4, (bytecode_p)__PREPARE_INSERT__p ); - if ($1.real->type == I_TYPE_UNKNOWN) - { - free_shared_identifier($1.real); - } - if (ix < 0) { switch(ix) { @@ -12709,7 +12798,7 @@ function_call: if (!realloc_a_program(1)) { - yyerrorf("Out of memory: program size %lu\n" + yyerrorf("Out of memory: program size %"PRIuMPINT"\n" , mem_block[A_PROGRAM].current_size + 2); YYACCEPT; } @@ -12746,7 +12835,7 @@ function_call: if (!disable_sefuns && call_other_sefun >= 0 - && call_other_sefun >= SEFUN_TABLE_SIZE) + && (unsigned long)call_other_sefun >= SEFUN_TABLE_SIZE) { /* The simul-efun has to be called by name: * insert the extra args for the call_other @@ -12756,7 +12845,7 @@ function_call: if (!realloc_a_program(6)) { - yyerrorf("Out of memory: program size %lu\n" + yyerrorf("Out of memory: program size %"PRIuMPINT"\n" , mem_block[A_PROGRAM].current_size + 2); YYACCEPT; } @@ -12851,7 +12940,8 @@ function_call: yyerrorf("Too many arguments to simul_efun %s" , get_txt(funp->name)); - if (call_other_sefun >= SEFUN_TABLE_SIZE) + /* call_other_sefun is >= 0 (see above) */ + if ((unsigned long)call_other_sefun >= SEFUN_TABLE_SIZE) { /* call-other: the number of arguments will be * detected and corrected at runtime. @@ -12876,7 +12966,7 @@ function_call: { if (!realloc_a_program(i+2)) { - yyerrorf("Out of memory: program size %lu\n" + yyerrorf("Out of memory: program size %"PRIuMPINT"\n" , mem_block[A_PROGRAM].current_size + i+2); YYACCEPT; } @@ -13145,8 +13235,6 @@ anchestor: L_IDENTIFIER { $$ = ystring_copy(get_txt($1->name)); - if ($1->type == I_TYPE_UNKNOWN) - free_shared_identifier($1); } | L_STRING L_STRING @@ -13222,7 +13310,7 @@ inline_fun: ); /* Restore the old locals information */ - leave_block_scope(); + leave_block_scope(MY_TRUE); use_local_scopes = pragma_use_local_scopes; all_locals = save_all_locals; current_number_of_locals = save_current_number_of_locals; @@ -13317,7 +13405,7 @@ catch: if (!realloc_a_program(5)) { - yyerrorf("Out of memory: program size %lu\n" + yyerrorf("Out of memory: program size %"PRIuMPINT"\n" , CURRENT_PROGRAM_SIZE + 5); YYACCEPT; } @@ -13802,14 +13890,24 @@ printf("DEBUG: context name '%s'\n", get_txt(name->name)); q = redeclare_local(name, actual_type, block_depth); else q = add_local_name(name, actual_type, block_depth); - if (use_local_scopes && scope->num_locals == 1) + + if (use_local_scopes && scope->clobbered) + { + /* finish the previous CLEAR_LOCALS, if any */ + if (scope->num_locals - 1 > scope->num_cleared) + mem_block[A_PROGRAM].block[scope->addr+2] + = (char)(scope->num_locals - 1 - scope->num_cleared); + scope->clobbered = MY_FALSE; + scope->num_cleared = scope->num_locals - 1; + } + if (use_local_scopes && scope->num_locals == scope->num_cleared + 1) { /* First definition of a local, so insert the * clear_locals bytecode and remember its position */ scope->addr = mem_block[A_PROGRAM].current_size; ins_f_code(F_CLEAR_LOCALS); - ins_byte(scope->first_local); + ins_byte(scope->first_local + scope->num_cleared); ins_byte(0); } @@ -13822,14 +13920,24 @@ printf("DEBUG: context name '%s'\n", get_txt(name->name)); else q = add_local_name(name, actual_type, block_depth, MY_FALSE); - if (use_local_scopes && scope->num_locals == 1) + if (use_local_scopes && scope->clobbered) + { + /* finish the previous CLEAR_LOCALS, if any */ + if (scope->num_locals - 1 > scope->num_cleared) + mem_block[A_PROGRAM].block[scope->addr+2] + = (char)(scope->num_locals - 1 - scope->num_cleared); + scope->clobbered = MY_FALSE; + scope->num_cleared = scope->num_locals - 1; + } + + if (use_local_scopes && scope->num_locals == scope->num_cleared + 1) { /* First definition of a local, so insert the * clear_locals bytecode and remember its position */ scope->addr = mem_block[A_PROGRAM].current_size; ins_f_code(F_CLEAR_LOCALS); - ins_byte(scope->first_local); + ins_byte(scope->first_local + scope->num_cleared); ins_byte(0); } @@ -13896,7 +14004,9 @@ init_local_variable ( ident_t* name, struct lvalue_s *lv, int assign_op %line #ifdef USE_NEW_INLINES #ifdef DEBUG_INLINES -if (current_inline && current_inline->parse_context) printf("DEBUG: inline context decl: name = expr, program_size %d\n", CURRENT_PROGRAM_SIZE); +if (current_inline && current_inline->parse_context) + printf("DEBUG: inline context decl: name = expr, program_size %"PRIuMPINT"\n", + CURRENT_PROGRAM_SIZE); #endif /* DEBUG_INLINES */ #endif /* USE_NEW_INLINES */ @@ -13960,7 +14070,7 @@ add_lvalue_code ( struct lvalue_s * lv, int instruction) current_size = CURRENT_PROGRAM_SIZE; if (!realloc_a_program(2)) { - yyerrorf("Out of memory: program size %lu" + yyerrorf("Out of memory: program size %"PRIuMPINT"\n" , current_size+2); return MY_FALSE; } @@ -14142,7 +14252,7 @@ arrange_protected_lvalue (p_int start, int code, p_int end, int newcode) /* Get enough memory */ if (!realloc_a_program(length)) { - yyerrorf("Out of memory: program size %lu\n" + yyerrorf("Out of memory: program size %"PRIuMPINT"\n" , CURRENT_PROGRAM_SIZE + length); return; } @@ -14212,7 +14322,7 @@ arrange_protected_lvalue (p_int start, int code, p_int end, int newcode) if (!realloc_a_program(2)) { - yyerrorf("Out of memory: program size %lu\n" + yyerrorf("Out of memory: program size %"PRIuMPINT"\n" , CURRENT_PROGRAM_SIZE + 2); return; } @@ -14252,7 +14362,7 @@ arrange_protected_lvalue (p_int start, int code, p_int end, int newcode) if (!realloc_a_program(2)) { - yyerrorf("Out of memory: program size %lu\n" + yyerrorf("Out of memory: program size %"PRIuMPINT"\n" , CURRENT_PROGRAM_SIZE + 2); return; } @@ -15175,8 +15285,8 @@ copy_functions (program_t *from, funflag_t type) q = xalloc(sizeof(efun_shadow_t)); if (!q) { - yyerrorf("Out of memory: efun shadow (%lu bytes)" - , (unsigned long) sizeof(efun_shadow_t)); + yyerrorf("Out of memory: efun shadow (%zu bytes)" + , sizeof(efun_shadow_t)); break; } q->shadow = p; @@ -15956,12 +16066,7 @@ printf("DEBUG: prolog: type ptrs: %p, %p\n", type_of_locals, type_of_context ); if (!id) fatal("Out of memory: identifier '%s'.\n", get_txt(STR_CALL_OTHER)); - if (id->type == I_TYPE_UNKNOWN) - { - /* No such identifier, therefor no such sefun */ - free_shared_identifier(id); - } - else + if (id->type != I_TYPE_UNKNOWN) { /* This shouldn't be necessary, but just in case... */ while (id && id->type > I_TYPE_GLOBAL) @@ -15988,7 +16093,8 @@ epilog (void) */ { - int size, i; + int i; + p_int size; mp_int num_functions; mp_int num_strings; mp_int num_variables; @@ -16132,7 +16238,7 @@ epilog (void) CURRENT_PROGRAM_SIZE = align(CURRENT_PROGRAM_SIZE); if (!realloc_a_program(FUNCTION_HDR_SIZE + 2)) { - yyerrorf("Out of memory: program size %lu\n" + yyerrorf("Out of memory: program size %"PRIuMPINT"\n" , CURRENT_PROGRAM_SIZE + FUNCTION_HDR_SIZE + 2); } else @@ -16352,6 +16458,8 @@ epilog (void) } all_globals = NULL; + + remove_unknown_identifier(); /* Now create the program structure */ switch (0) { default: @@ -16365,14 +16473,15 @@ epilog (void) { struct_type_t * ptype; ptype = STRUCT_DEF(i).type; - printf("DEBUG: [%d] struct %s: (%s #%ld) ref %ld, %d members, base %s, flags %lx\n" + printf("DEBUG: [%d] struct %s: (%s #%"PRId32") ref %"PRIdPINT + ", %hd members, base %s, flags %"PRIx32"\n" , i, get_txt(ptype->name) , ptype->prog_name ? get_txt(ptype->prog_name) : "" - , (long)ptype->prog_id - , (long)ptype->ref + , ptype->prog_id + , ptype->ref , ptype->num_members , ptype->base ? get_txt(ptype->base->name) : "" - , (long)STRUCT_DEF(i).flags + , STRUCT_DEF(i).flags ); fflush(stdout); #if 1 @@ -16423,7 +16532,8 @@ epilog (void) /* Get the program structure */ if ( !(p = xalloc(size)) ) { - yyerrorf("Out of memory: program structure (%u bytes)", size); + yyerrorf("Out of memory: program structure (%"PRIdPINT" bytes)", + size); break; } @@ -16593,8 +16703,8 @@ epilog (void) total_prog_block_size -= prog->total_size + mstrsize(prog->name)+1; total_num_prog_blocks -= 1; xfree(prog); - yyerrorf("Out of memory: linenumber structure (%lu bytes)" - , (unsigned long)linenumber_size); + yyerrorf("Out of memory: linenumber structure (%zu bytes)" + , linenumber_size); break; } total_prog_block_size += linenumber_size; diff --git a/src/ptrtable.c b/src/ptrtable.c index 19c3d71..78bd8e1 100644 --- a/src/ptrtable.c +++ b/src/ptrtable.c @@ -127,7 +127,7 @@ find_add_pointer (struct pointer_table *ptable, void *pointer, Bool bAdd) */ { - mp_int key; /* The as a normal int */ + p_uint key; /* The as a normal int */ int hash; /* hash computed from aka */ int mask; /* mask for in to */ char *usage_p; /* First usage vector byte for entry */ @@ -135,7 +135,7 @@ find_add_pointer (struct pointer_table *ptable, void *pointer, Bool bAdd) struct pointer_record *new; /* New record to add */ struct pointer_record **insert; /* Pointer to hashed table entry */ - key = (mp_int)pointer; + key = (p_uint)pointer; /* Compute the hash value, and the index and mask for * the usage vector @@ -214,8 +214,8 @@ find_add_pointer (struct pointer_table *ptable, void *pointer, Bool bAdd) table = mempool_alloc(ptable->pool, sizeof *table); if (!table) - errorf("(pointertable) Out of memory (%lu bytes pooled) " - "for subtable.\n", (unsigned long) sizeof *table); + errorf("(pointertable) Out of memory (%zu bytes pooled) " + "for subtable.\n", sizeof *table); *insert = (struct pointer_record *)table; memset(table->used, 0, sizeof table->used); @@ -247,8 +247,8 @@ find_add_pointer (struct pointer_table *ptable, void *pointer, Bool bAdd) usage_p[0] |= mask; new = mempool_alloc(ptable->pool, sizeof *new); if (!new) - errorf("(pointertable) Out of memory (%lu bytes pooled) for " - "new entry.\n", (unsigned long) sizeof *new); + errorf("(pointertable) Out of memory (%zu bytes pooled) for " + "new entry.\n", sizeof *new); *insert = new; new->key = key; new->next = old; diff --git a/src/random.c b/src/random.c index 1541603..0a95499 100644 --- a/src/random.c +++ b/src/random.c @@ -1,274 +1,120 @@ -/*--------------------------------------------------------------------------- - * Gamedriver: Random Generator 'Mersenne Twister' +/*------------------------------------------------------------------ + * Wrapper for the 'SIMD oriented Fast Mersenne Twister. * - * A C-program for MT19937, with initialization improved 2002/2/10. - * Coded by Takuji Nishimura and Makoto Matsumoto. - * This is a faster version by taking Shawn Cokus's optimization, - * Matthe Bellew's simplification, Isaku Wada's real version. - * - * Before using, initialize the state by using init_genrand(seed) - * or init_by_array(init_key, key_length). - * - * Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura, - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. The names of its contributors may not 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. - * - * Any feedback is very welcome. - * http://www.math.keio.ac.jp/matumoto/emt.html - * email: matumoto@math.keio.ac.jp - *--------------------------------------------------------------------------- + * SFMT was developed by Mutsuo Saito and Makoto Matsumoto, + * Hiroshima University, + * http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/SFMT/index.html) + * SFMT was integrated to LDMud by Zesstra@MorgenGrauen (http://mg.mud.de) + *------------------------------------------------------------------ */ #include "driver.h" #include "random.h" +#include "backend.h" -/* Period parameters */ -#define N 624 -#define M 397 -#define MATRIX_A 0x9908b0dfUL /* constant vector a */ -#define UMASK 0x80000000UL /* most significant w-r bits */ -#define LMASK 0x7fffffffUL /* least significant r bits */ -#define MIXBITS(u,v) ( ((u) & UMASK) | ((v) & LMASK) ) -#define TWIST(u,v) ((MIXBITS(u,v) >> 1) ^ ((v)&1UL ? MATRIX_A : 0UL)) +/* This is included on purpose so that the compiler may inline some functions. + * They are anyway never used anywhere else, all other parts of the driver use + * only the wrapper functions in this file. + */ +#include "random/SFMT.c" -static unsigned long state[N]; /* the array for the state vector */ -static int left = 1; -static int initf = 0; -static unsigned long *next; +const unsigned int INIT_ARRAY_SIZE = 156U; // 4*156 == 624 bytes -/* initializes state[N] with a seed */ -void init_genrand(unsigned long s) -{ - int j; - state[0]= s & 0xffffffffUL; - for (j=1; j> 30)) + j); - /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */ - /* In the previous versions, MSBs of the seed affect */ - /* only MSBs of the array state[]. */ - /* 2002/01/09 modified by Makoto Matsumoto */ - state[j] &= 0xffffffffUL; /* for >32 bit machines */ - } - left = 1; initf = 1; -} - -/* initialize by an array with array-length */ -/* init_key is the array for initializing keys */ -/* key_length is its length */ -/* slight change for C++, 2004/2/26 */ -void init_by_array(unsigned long init_key[], int key_length) -{ - int i, j, k; - init_genrand(19650218UL); - i=1; j=0; - k = (N>key_length ? N : key_length); - for (; k; k--) { - state[i] = (state[i] ^ ((state[i-1] ^ (state[i-1] >> 30)) * 1664525UL)) - + init_key[j] + j; /* non linear */ - state[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */ - i++; j++; - if (i>=N) { state[0] = state[N-1]; i=1; } - if (j>=key_length) j=0; - } - for (k=N-1; k; k--) { - state[i] = (state[i] ^ ((state[i-1] ^ (state[i-1] >> 30)) * 1566083941UL)) - - i; /* non linear */ - state[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */ - i++; - if (i>=N) { state[0] = state[N-1]; i=1; } - } - - state[0] = 0x80000000UL; /* MSB is 1; assuring non-zero initial array */ - left = 1; initf = 1; -} - -static void next_state(void) -{ - unsigned long *p=state; - int j; - - /* if init_genrand() has not been called, */ - /* a default initial seed is used */ - if (initf==0) init_genrand(5489UL); - - left = N; - next = state; - - for (j=N-M+1; --j; p++) - *p = p[M] ^ TWIST(p[0], p[1]); - - for (j=M; --j; p++) - *p = p[M-N] ^ TWIST(p[0], p[1]); - - *p = p[M-N] ^ TWIST(p[0], state[0]); -} - -/* generates a random number on [0,0xffffffff]-interval */ -unsigned long genrand_int32(void) -{ - unsigned long y; - - if (--left == 0) next_state(); - y = *next++; - - /* Tempering */ - y ^= (y >> 11); - y ^= (y << 7) & 0x9d2c5680UL; - y ^= (y << 15) & 0xefc60000UL; - y ^= (y >> 18); - - return y; -} - -#if 0 - -/** LDMud doesn't use the following functions - yet. **/ - -/* generates a random number on [0,0x7fffffff]-interval */ -long genrand_int31(void) -{ - unsigned long y; - - if (--left == 0) next_state(); - y = *next++; - - /* Tempering */ - y ^= (y >> 11); - y ^= (y << 7) & 0x9d2c5680UL; - y ^= (y << 15) & 0xefc60000UL; - y ^= (y >> 18); - - return (long)(y>>1); -} - -/* generates a random number on [0,1]-real-interval */ -double genrand_real1(void) -{ - unsigned long y; - - if (--left == 0) next_state(); - y = *next++; - - /* Tempering */ - y ^= (y >> 11); - y ^= (y << 7) & 0x9d2c5680UL; - y ^= (y << 15) & 0xefc60000UL; - y ^= (y >> 18); - - return (double)y * (1.0/4294967295.0); - /* divided by 2^32-1 */ -} - -/* generates a random number on [0,1)-real-interval */ -double genrand_real2(void) -{ - unsigned long y; - - if (--left == 0) next_state(); - y = *next++; - - /* Tempering */ - y ^= (y >> 11); - y ^= (y << 7) & 0x9d2c5680UL; - y ^= (y << 15) & 0xefc60000UL; - y ^= (y >> 18); - - return (double)y * (1.0/4294967296.0); - /* divided by 2^32 */ -} - -/* generates a random number on (0,1)-real-interval */ -double genrand_real3(void) -{ - unsigned long y; - - if (--left == 0) next_state(); - y = *next++; - - /* Tempering */ - y ^= (y >> 11); - y ^= (y << 7) & 0x9d2c5680UL; - y ^= (y << 15) & 0xefc60000UL; - y ^= (y >> 18); - - return ((double)y + 0.5) * (1.0/4294967296.0); - /* divided by 2^32 */ -} - -/* generates a random number on [0,1) with 53-bit resolution*/ -double genrand_res53(void) -{ - unsigned long a=genrand_int32()>>5, b=genrand_int32()>>6; - return(a*67108864.0+b)*(1.0/9007199254740992.0); -} -/* These real versions are due to Isaku Wada, 2002/01/09 added */ - -#endif +// Name of the device/file to seed the PRNG from +char * prng_device_name = NULL; /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ /* Driver interface functions */ - /*-------------------------------------------------------------------------*/ -void -seed_random (uint32 seed) - -/* Initialize the generator */ - -{ - unsigned long init[4]; - init[0] = seed & 0xFFF; - init[1] = (seed >>= 8) & 0xFFF; - init[2] = (seed >>= 8) & 0xFFF; - init[3] = (seed >>= 8) & 0xFFF; - init_by_array(init, 4); -} /* seed_random() */ - -/*-------------------------------------------------------------------------*/ -uint32 -random_number (uint32 n) +/* random_number() is in random.h to be inlined. */ /* Return a random number in the range 0..n-1. * * The MT FAQ suggests: * If the application is not sensitive to the rounding off error, then please * multiply N to [0,1)-real uniform random numbers and take the integer part * (this is sufficient for most applications). - * + * I use the appropriate functions from the SFMT to generate random numbers on + * the [0,1) interval and multiply with N. */ +#if SIZEOF_LONG == SIZEOF_CHAR_P +uint64_t random_number(uint64_t n) { + return genrand_res53() * n; +} +#elif SIZEOF_INT == SIZEOF_CHAR_P +uint32_t random_number(uint32 n) { + return genrand_real2() * n; +} +#else +#error We currently do not yet support a 128 bit integer type used as \ + svalue number type. +#endif + +void seed_random_from_int (uint32_t seed) +/* Initialize the generator */ { - return genrand_int32() * (1.0/4294967296.0) * n; - /* - * Since most compilers compute the constant when it is compiled, so this - * code runs with the same speed with the standard C codes, and portability - * and readability are better. - */ -} /* random_number() */ +#ifdef USE_LDMUD_COMPATIBILITY +# ifdef VERBOSE + printf("%s Seeding PRNG with: 0x%lx\n" + , time_stamp(), (unsigned long)seed); +# endif + debug_message("%s Seeding PRNG with: 0x%lx\n" + , time_stamp(), (unsigned long)seed); +#endif + init_gen_rand(seed); +} /* seed_random_from_int() */ + +/*-------------------------------------------------------------------------*/ + +void +seed_random(const char *filename) + /* Opens the file given by filename and reads 156 uint32_t (624 + * bytes) from it (most often the file is probably /dev/urandom or + * /dev/random). If successful the random number generator will be seeded + * by an array of 624 bytes. Otherwise the driver clock will be used as + * fallback. + */ +{ + FILE *seedsrc = NULL; // Filepointer + + // If we got a NULL pointer or an empty string, don't try to open some + // device/file. + if (filename != NULL && strlen(filename)) + seedsrc = fopen(filename,"rb"); + + // if we have a file descriptor try to get a suitable amount of 32-bit + // values from a file (right now 156 uint32_t / 624 bytes) + if (seedsrc) { + uint32_t seeddata[INIT_ARRAY_SIZE]; + size_t count = fread( seeddata, sizeof(uint32), INIT_ARRAY_SIZE, + seedsrc ); + fclose(seedsrc); + if( count == INIT_ARRAY_SIZE ) { + init_by_array(seeddata, INIT_ARRAY_SIZE ); // seed PRNG +#ifdef USE_LDMUD_COMPATIBILITY +# ifdef VERBOSE + printf("%s Seeding PRNG from %s.\n", time_stamp(), + filename); +# endif + debug_message("%s Seeding PRNG from %s.\n", time_stamp(), + filename); +#endif + return; + } // if (count == INIT_ARRAY_SIZE) + } // if (seedsrc) + + // Fall-back: driver clock +#ifdef USE_LDMUD_COMPATIBILITY +# ifdef VERBOSE + printf("%s Seeding PRNG with current driver time\n" + , time_stamp()); +# endif + debug_message("%s Seeding PRNG with current driver time\n" + , time_stamp()); +#endif + seed_random_from_int((uint32_t)current_time); + +} /* seed_random() */ /***************************************************************************/ diff --git a/src/random.h b/src/random.h index 6327425..daec788 100644 --- a/src/random.h +++ b/src/random.h @@ -2,8 +2,28 @@ #define RANDOM_H__ 1 #include "driver.h" +// SFTM expects MEXP to contain the desired period length +#ifdef RANDOM_PERIOD_LENGTH +#define MEXP RANDOM_PERIOD_LENGTH +#endif -extern uint32 random_number(uint32 n); -extern void seed_random(uint32 seed); +#include "random/SFMT.h" + +#define PRNG_DEFAULT_DEVICE "/dev/urandom" + +// device/file to read seed for the PRNG from +extern char * prng_device_name; + +/* --- Prototypes --- */ +extern void seed_random_from_int(uint32_t seed); +extern void seed_random(const char *filename); +#if SIZEOF_LONG == SIZEOF_CHAR_P +uint64_t random_number(uint64_t n); +#elif SIZEOF_INT == SIZEOF_CHAR_P +uint32_t random_number(uint32_t n); +#else +#error We currently do not yes support a 128 bit integer type used as \ + svalue number type. +#endif #endif /* RANDOM_H__ */ diff --git a/src/random/CHANGE-LOG.txt b/src/random/CHANGE-LOG.txt new file mode 100644 index 0000000..c73fcf1 --- /dev/null +++ b/src/random/CHANGE-LOG.txt @@ -0,0 +1,55 @@ +ver 1.3.3 +------- +change condition compile of do_recursion in SFMT.c + +ver 1.3.2 +------- +bug fix to_res53_mix and genrand_res53_mix. + +ver 1.3.1 +------- +gcc compile option changed form -O9 to -O3. +add functions genrand_res53_mix and to_res53_mix. +bug fix about definition of ALWAYS_INLINE. +add new definition PRE_ALWAYS for MSC. + +ver 1.3 +------- +bug fixed: -DONLY64 without -DBIG_ENIAN64 had been generating +wrong sequence. +bug fixed: There is no documentation about BIG_ENDIAN64. +add automatic endian check by __BIG_ENDIAN__ predefined macro. +bug fixed: change == in check.sh to = +add SFMT-params216091.h +add AltiVec parameter format for systems which are not osx. +change Makefile for systems which are not osx and support AltiVec. +change sample2 of howto-compile for Free BSD. +change source files for BORLANDC and Visual Studio. +change period certification code more smart. +add params directory. + +ver 1.2.1 +------- +Fix typo in SFMT-alti.c SFMT-sse2.c +marge SFMT-alti.c and SFMT-alti.h into SFMT-alti.h +marge SFMT-sse2.c and SFMT-sse2.h into SFMT-sse2.h +This version is not released. + +ver 1.2 +------- +Support many periods: 2^{607}, 2^{1279}, 2^{2281}, 2^{4253}, 2^{11213}, +2^{19937}, 2^{44497}, 2^{86243}, 2^{132049} +Fix typo in LICENSE.txt. +Add cast to vec_perm for SFMT-alti.c, SFMT-alti64.c. +combine source codes. + +ver 1.1 +------- +The period certification method is changed from constant to function. +The convert functions from 32-bit and 64-bit integer to double are added. +The documentation is changed. +Sample programs are added. + +ver 1.0 +------- +The first version. diff --git a/src/random/FILES.txt b/src/random/FILES.txt new file mode 100644 index 0000000..74c0b86 --- /dev/null +++ b/src/random/FILES.txt @@ -0,0 +1,21 @@ +This archive contails following directories and files. + +TOP DIRECTORY +FILES.txt: This file. +LICENSE.txt: License file. +CHANGE-LOG.txt: Change log file. +SFMT.h: Header file. +SFMT-params.h: parameter file which controls various Mersenne expornent +params607.h: parameters for period of 2^{607}-1 +params1279.h: parameters for period of 2^{1279}-1 +params2281.h: parameters for period of 2^{2281}-1 +params4253.h: parameters for period of 2^{4253}-1 +params11213.h: parameters for period of 2^{11213}-1 +params19937.h: parameters for period of 2^{19937}-1 +params44497.h: parameters for period of 2^{44497}-1 +params86243.h: parameters for period of 2^{86243}-1 +params132049.h: parameters for period of 2^{132049}-1 +params216091.h: parameters for period of 2^{216091}-1 +SFMT.c: C code for standard C (c99) and unix like systems. +SFMT-alti.h: C code optimized for PowerPC AltiVec. +SFMT-sse2.h: C code optimized for intel SSE2. diff --git a/src/random/LICENSE.txt b/src/random/LICENSE.txt new file mode 100644 index 0000000..9e2e6b5 --- /dev/null +++ b/src/random/LICENSE.txt @@ -0,0 +1,32 @@ +This License covers the the files in this subdirectory of the LDMud +source (src/random/). + +Copyright (c) 2006,2007 Mutsuo Saito, Makoto Matsumoto and Hiroshima +University. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of the Hiroshima University nor the names of + its contributors may be used to endorse or promote products + derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/src/random/README.LDMUD b/src/random/README.LDMUD new file mode 100644 index 0000000..25672df --- /dev/null +++ b/src/random/README.LDMUD @@ -0,0 +1,10 @@ +This is SFMT-1.3.3, stripped down to what is required by the LDMud gamedriver. + +Additionally the 'public' function were made static as well because they are +probably not used without the wrapper. Therefore, their declarations have been +commented out. +The small inline functions from SFMT.h were moved to SFMT.c for the same +reason. + +The files README.txt and LICENSE.txt tell you where to get the complete package. + diff --git a/src/random/README.txt b/src/random/README.txt new file mode 100644 index 0000000..59ae23a --- /dev/null +++ b/src/random/README.txt @@ -0,0 +1,22 @@ + ================================================================= + SFMT ver. 1.3.3 + SIMD oriented Fast Mersenne Twister(SFMT) + + Mutsuo Saito (Hiroshima University) and + Makoto Matsumoto (Hiroshima University) + + Copyright (C) 2006, 2007 Mutsuo Saito, Makoto Matsumoto and Hiroshima + University. All rights reserved. + + The (modified) BSD License is applied to this software, see LICENSE.txt + ================================================================= + + To see documents, see html/index.html. + + To make test program, see html/howto-compile.html + + If you want to redistribute and/or change source files, see LICENSE.txt. + + When you change these files and redistribute them, PLEASE write your + e-mail address in redistribution and write to contact YOU first if + users of your changed source encounter troubles. diff --git a/src/random/SFMT-alti.h b/src/random/SFMT-alti.h new file mode 100644 index 0000000..df3186c --- /dev/null +++ b/src/random/SFMT-alti.h @@ -0,0 +1,156 @@ +/** + * @file SFMT-alti.h + * + * @brief SIMD oriented Fast Mersenne Twister(SFMT) + * pseudorandom number generator + * + * @author Mutsuo Saito (Hiroshima University) + * @author Makoto Matsumoto (Hiroshima University) + * + * Copyright (C) 2007 Mutsuo Saito, Makoto Matsumoto and Hiroshima + * University. All rights reserved. + * + * The new BSD License is applied to this software. + * see LICENSE.txt + */ + +#ifndef SFMT_ALTI_H +#define SFMT_ALTI_H + +inline static vector unsigned int vec_recursion(vector unsigned int a, + vector unsigned int b, + vector unsigned int c, + vector unsigned int d) + ALWAYSINLINE; + +/** + * This function represents the recursion formula in AltiVec and BIG ENDIAN. + * @param a a 128-bit part of the interal state array + * @param b a 128-bit part of the interal state array + * @param c a 128-bit part of the interal state array + * @param d a 128-bit part of the interal state array + * @return output + */ +inline static vector unsigned int vec_recursion(vector unsigned int a, + vector unsigned int b, + vector unsigned int c, + vector unsigned int d) { + + const vector unsigned int sl1 = ALTI_SL1; + const vector unsigned int sr1 = ALTI_SR1; +#ifdef ONLY64 + const vector unsigned int mask = ALTI_MSK64; + const vector unsigned char perm_sl = ALTI_SL2_PERM64; + const vector unsigned char perm_sr = ALTI_SR2_PERM64; +#else + const vector unsigned int mask = ALTI_MSK; + const vector unsigned char perm_sl = ALTI_SL2_PERM; + const vector unsigned char perm_sr = ALTI_SR2_PERM; +#endif + vector unsigned int v, w, x, y, z; + x = vec_perm(a, (vector unsigned int)perm_sl, perm_sl); + v = a; + y = vec_sr(b, sr1); + z = vec_perm(c, (vector unsigned int)perm_sr, perm_sr); + w = vec_sl(d, sl1); + z = vec_xor(z, w); + y = vec_and(y, mask); + v = vec_xor(v, x); + z = vec_xor(z, y); + z = vec_xor(z, v); + return z; +} + +/** + * This function fills the internal state array with pseudorandom + * integers. + */ +inline static void gen_rand_all(void) { + int i; + vector unsigned int r, r1, r2; + + r1 = sfmt[N - 2].s; + r2 = sfmt[N - 1].s; + for (i = 0; i < N - POS1; i++) { + r = vec_recursion(sfmt[i].s, sfmt[i + POS1].s, r1, r2); + sfmt[i].s = r; + r1 = r2; + r2 = r; + } + for (; i < N; i++) { + r = vec_recursion(sfmt[i].s, sfmt[i + POS1 - N].s, r1, r2); + sfmt[i].s = r; + r1 = r2; + r2 = r; + } +} + +/** + * This function fills the user-specified array with pseudorandom + * integers. + * + * @param array an 128-bit array to be filled by pseudorandom numbers. + * @param size number of 128-bit pesudorandom numbers to be generated. + */ +inline static void gen_rand_array(w128_t *array, int size) { + int i, j; + vector unsigned int r, r1, r2; + + r1 = sfmt[N - 2].s; + r2 = sfmt[N - 1].s; + for (i = 0; i < N - POS1; i++) { + r = vec_recursion(sfmt[i].s, sfmt[i + POS1].s, r1, r2); + array[i].s = r; + r1 = r2; + r2 = r; + } + for (; i < N; i++) { + r = vec_recursion(sfmt[i].s, array[i + POS1 - N].s, r1, r2); + array[i].s = r; + r1 = r2; + r2 = r; + } + /* main loop */ + for (; i < size - N; i++) { + r = vec_recursion(array[i - N].s, array[i + POS1 - N].s, r1, r2); + array[i].s = r; + r1 = r2; + r2 = r; + } + for (j = 0; j < 2 * N - size; j++) { + sfmt[j].s = array[j + size - N].s; + } + for (; i < size; i++) { + r = vec_recursion(array[i - N].s, array[i + POS1 - N].s, r1, r2); + array[i].s = r; + sfmt[j++].s = r; + r1 = r2; + r2 = r; + } +} + +#ifndef ONLY64 +#if defined(__APPLE__) +#define ALTI_SWAP (vector unsigned char) \ + (4, 5, 6, 7, 0, 1, 2, 3, 12, 13, 14, 15, 8, 9, 10, 11) +#else +#define ALTI_SWAP {4, 5, 6, 7, 0, 1, 2, 3, 12, 13, 14, 15, 8, 9, 10, 11} +#endif +/** + * This function swaps high and low 32-bit of 64-bit integers in user + * specified array. + * + * @param array an 128-bit array to be swaped. + * @param size size of 128-bit array. + */ +inline static void swap(w128_t *array, int size) { + int i; + const vector unsigned char perm = ALTI_SWAP; + + for (i = 0; i < size; i++) { + array[i].s = vec_perm(array[i].s, (vector unsigned int)perm, perm); + } +} +#endif + +#endif diff --git a/src/random/SFMT-params.h b/src/random/SFMT-params.h new file mode 100644 index 0000000..661bbf2 --- /dev/null +++ b/src/random/SFMT-params.h @@ -0,0 +1,97 @@ +#ifndef SFMT_PARAMS_H +#define SFMT_PARAMS_H + +#if !defined(MEXP) +#ifdef __GNUC__ + #warning "MEXP is not defined. I assume MEXP is 19937." +#endif + #define MEXP 19937 +#endif +/*----------------- + BASIC DEFINITIONS + -----------------*/ +/** Mersenne Exponent. The period of the sequence + * is a multiple of 2^MEXP-1. + * #define MEXP 19937 */ +/** SFMT generator has an internal state array of 128-bit integers, + * and N is its size. */ +#define N (MEXP / 128 + 1) +/** N32 is the size of internal state array when regarded as an array + * of 32-bit integers.*/ +#define N32 (N * 4) +/** N64 is the size of internal state array when regarded as an array + * of 64-bit integers.*/ +#define N64 (N * 2) + +/*---------------------- + the parameters of SFMT + following definitions are in paramsXXXX.h file. + ----------------------*/ +/** the pick up position of the array. +#define POS1 122 +*/ + +/** the parameter of shift left as four 32-bit registers. +#define SL1 18 + */ + +/** the parameter of shift left as one 128-bit register. + * The 128-bit integer is shifted by (SL2 * 8) bits. +#define SL2 1 +*/ + +/** the parameter of shift right as four 32-bit registers. +#define SR1 11 +*/ + +/** the parameter of shift right as one 128-bit register. + * The 128-bit integer is shifted by (SL2 * 8) bits. +#define SR2 1 +*/ + +/** A bitmask, used in the recursion. These parameters are introduced + * to break symmetry of SIMD. +#define MSK1 0xdfffffefU +#define MSK2 0xddfecb7fU +#define MSK3 0xbffaffffU +#define MSK4 0xbffffff6U +*/ + +/** These definitions are part of a 128-bit period certification vector. +#define PARITY1 0x00000001U +#define PARITY2 0x00000000U +#define PARITY3 0x00000000U +#define PARITY4 0xc98e126aU +*/ + +#if MEXP == 607 + #include "SFMT-params607.h" +#elif MEXP == 1279 + #include "SFMT-params1279.h" +#elif MEXP == 2281 + #include "SFMT-params2281.h" +#elif MEXP == 4253 + #include "SFMT-params4253.h" +#elif MEXP == 11213 + #include "SFMT-params11213.h" +#elif MEXP == 19937 + #include "SFMT-params19937.h" +#elif MEXP == 44497 + #include "SFMT-params44497.h" +#elif MEXP == 86243 + #include "SFMT-params86243.h" +#elif MEXP == 132049 + #include "SFMT-params132049.h" +#elif MEXP == 216091 + #include "SFMT-params216091.h" +#else +#ifdef __GNUC__ + #error "MEXP is not valid." + #undef MEXP +#else + #undef MEXP +#endif + +#endif + +#endif /* SFMT_PARAMS_H */ diff --git a/src/random/SFMT-params11213.h b/src/random/SFMT-params11213.h new file mode 100644 index 0000000..244d313 --- /dev/null +++ b/src/random/SFMT-params11213.h @@ -0,0 +1,46 @@ +#ifndef SFMT_PARAMS11213_H +#define SFMT_PARAMS11213_H + +#define POS1 68 +#define SL1 14 +#define SL2 3 +#define SR1 7 +#define SR2 3 +#define MSK1 0xeffff7fbU +#define MSK2 0xffffffefU +#define MSK3 0xdfdfbfffU +#define MSK4 0x7fffdbfdU +#define PARITY1 0x00000001U +#define PARITY2 0x00000000U +#define PARITY3 0xe8148000U +#define PARITY4 0xd0c7afa3U + + +/* PARAMETERS FOR ALTIVEC */ +#if defined(__APPLE__) /* For OSX */ + #define ALTI_SL1 (vector unsigned int)(SL1, SL1, SL1, SL1) + #define ALTI_SR1 (vector unsigned int)(SR1, SR1, SR1, SR1) + #define ALTI_MSK (vector unsigned int)(MSK1, MSK2, MSK3, MSK4) + #define ALTI_MSK64 \ + (vector unsigned int)(MSK2, MSK1, MSK4, MSK3) + #define ALTI_SL2_PERM \ + (vector unsigned char)(3,21,21,21,7,0,1,2,11,4,5,6,15,8,9,10) + #define ALTI_SL2_PERM64 \ + (vector unsigned char)(3,4,5,6,7,29,29,29,11,12,13,14,15,0,1,2) + #define ALTI_SR2_PERM \ + (vector unsigned char)(5,6,7,0,9,10,11,4,13,14,15,8,19,19,19,12) + #define ALTI_SR2_PERM64 \ + (vector unsigned char)(13,14,15,0,1,2,3,4,19,19,19,8,9,10,11,12) +#else /* For OTHER OSs(Linux?) */ + #define ALTI_SL1 {SL1, SL1, SL1, SL1} + #define ALTI_SR1 {SR1, SR1, SR1, SR1} + #define ALTI_MSK {MSK1, MSK2, MSK3, MSK4} + #define ALTI_MSK64 {MSK2, MSK1, MSK4, MSK3} + #define ALTI_SL2_PERM {3,21,21,21,7,0,1,2,11,4,5,6,15,8,9,10} + #define ALTI_SL2_PERM64 {3,4,5,6,7,29,29,29,11,12,13,14,15,0,1,2} + #define ALTI_SR2_PERM {5,6,7,0,9,10,11,4,13,14,15,8,19,19,19,12} + #define ALTI_SR2_PERM64 {13,14,15,0,1,2,3,4,19,19,19,8,9,10,11,12} +#endif /* For OSX */ +#define IDSTR "SFMT-11213:68-14-3-7-3:effff7fb-ffffffef-dfdfbfff-7fffdbfd" + +#endif /* SFMT_PARAMS11213_H */ diff --git a/src/random/SFMT-params1279.h b/src/random/SFMT-params1279.h new file mode 100644 index 0000000..df538df --- /dev/null +++ b/src/random/SFMT-params1279.h @@ -0,0 +1,46 @@ +#ifndef SFMT_PARAMS1279_H +#define SFMT_PARAMS1279_H + +#define POS1 7 +#define SL1 14 +#define SL2 3 +#define SR1 5 +#define SR2 1 +#define MSK1 0xf7fefffdU +#define MSK2 0x7fefcfffU +#define MSK3 0xaff3ef3fU +#define MSK4 0xb5ffff7fU +#define PARITY1 0x00000001U +#define PARITY2 0x00000000U +#define PARITY3 0x00000000U +#define PARITY4 0x20000000U + + +/* PARAMETERS FOR ALTIVEC */ +#if defined(__APPLE__) /* For OSX */ + #define ALTI_SL1 (vector unsigned int)(SL1, SL1, SL1, SL1) + #define ALTI_SR1 (vector unsigned int)(SR1, SR1, SR1, SR1) + #define ALTI_MSK (vector unsigned int)(MSK1, MSK2, MSK3, MSK4) + #define ALTI_MSK64 \ + (vector unsigned int)(MSK2, MSK1, MSK4, MSK3) + #define ALTI_SL2_PERM \ + (vector unsigned char)(3,21,21,21,7,0,1,2,11,4,5,6,15,8,9,10) + #define ALTI_SL2_PERM64 \ + (vector unsigned char)(3,4,5,6,7,29,29,29,11,12,13,14,15,0,1,2) + #define ALTI_SR2_PERM \ + (vector unsigned char)(7,0,1,2,11,4,5,6,15,8,9,10,17,12,13,14) + #define ALTI_SR2_PERM64 \ + (vector unsigned char)(15,0,1,2,3,4,5,6,17,8,9,10,11,12,13,14) +#else /* For OTHER OSs(Linux?) */ + #define ALTI_SL1 {SL1, SL1, SL1, SL1} + #define ALTI_SR1 {SR1, SR1, SR1, SR1} + #define ALTI_MSK {MSK1, MSK2, MSK3, MSK4} + #define ALTI_MSK64 {MSK2, MSK1, MSK4, MSK3} + #define ALTI_SL2_PERM {3,21,21,21,7,0,1,2,11,4,5,6,15,8,9,10} + #define ALTI_SL2_PERM64 {3,4,5,6,7,29,29,29,11,12,13,14,15,0,1,2} + #define ALTI_SR2_PERM {7,0,1,2,11,4,5,6,15,8,9,10,17,12,13,14} + #define ALTI_SR2_PERM64 {15,0,1,2,3,4,5,6,17,8,9,10,11,12,13,14} +#endif /* For OSX */ +#define IDSTR "SFMT-1279:7-14-3-5-1:f7fefffd-7fefcfff-aff3ef3f-b5ffff7f" + +#endif /* SFMT_PARAMS1279_H */ diff --git a/src/random/SFMT-params132049.h b/src/random/SFMT-params132049.h new file mode 100644 index 0000000..94e297e --- /dev/null +++ b/src/random/SFMT-params132049.h @@ -0,0 +1,46 @@ +#ifndef SFMT_PARAMS132049_H +#define SFMT_PARAMS132049_H + +#define POS1 110 +#define SL1 19 +#define SL2 1 +#define SR1 21 +#define SR2 1 +#define MSK1 0xffffbb5fU +#define MSK2 0xfb6ebf95U +#define MSK3 0xfffefffaU +#define MSK4 0xcff77fffU +#define PARITY1 0x00000001U +#define PARITY2 0x00000000U +#define PARITY3 0xcb520000U +#define PARITY4 0xc7e91c7dU + + +/* PARAMETERS FOR ALTIVEC */ +#if defined(__APPLE__) /* For OSX */ + #define ALTI_SL1 (vector unsigned int)(SL1, SL1, SL1, SL1) + #define ALTI_SR1 (vector unsigned int)(SR1, SR1, SR1, SR1) + #define ALTI_MSK (vector unsigned int)(MSK1, MSK2, MSK3, MSK4) + #define ALTI_MSK64 \ + (vector unsigned int)(MSK2, MSK1, MSK4, MSK3) + #define ALTI_SL2_PERM \ + (vector unsigned char)(1,2,3,23,5,6,7,0,9,10,11,4,13,14,15,8) + #define ALTI_SL2_PERM64 \ + (vector unsigned char)(1,2,3,4,5,6,7,31,9,10,11,12,13,14,15,0) + #define ALTI_SR2_PERM \ + (vector unsigned char)(7,0,1,2,11,4,5,6,15,8,9,10,17,12,13,14) + #define ALTI_SR2_PERM64 \ + (vector unsigned char)(15,0,1,2,3,4,5,6,17,8,9,10,11,12,13,14) +#else /* For OTHER OSs(Linux?) */ + #define ALTI_SL1 {SL1, SL1, SL1, SL1} + #define ALTI_SR1 {SR1, SR1, SR1, SR1} + #define ALTI_MSK {MSK1, MSK2, MSK3, MSK4} + #define ALTI_MSK64 {MSK2, MSK1, MSK4, MSK3} + #define ALTI_SL2_PERM {1,2,3,23,5,6,7,0,9,10,11,4,13,14,15,8} + #define ALTI_SL2_PERM64 {1,2,3,4,5,6,7,31,9,10,11,12,13,14,15,0} + #define ALTI_SR2_PERM {7,0,1,2,11,4,5,6,15,8,9,10,17,12,13,14} + #define ALTI_SR2_PERM64 {15,0,1,2,3,4,5,6,17,8,9,10,11,12,13,14} +#endif /* For OSX */ +#define IDSTR "SFMT-132049:110-19-1-21-1:ffffbb5f-fb6ebf95-fffefffa-cff77fff" + +#endif /* SFMT_PARAMS132049_H */ diff --git a/src/random/SFMT-params19937.h b/src/random/SFMT-params19937.h new file mode 100644 index 0000000..04708cd --- /dev/null +++ b/src/random/SFMT-params19937.h @@ -0,0 +1,46 @@ +#ifndef SFMT_PARAMS19937_H +#define SFMT_PARAMS19937_H + +#define POS1 122 +#define SL1 18 +#define SL2 1 +#define SR1 11 +#define SR2 1 +#define MSK1 0xdfffffefU +#define MSK2 0xddfecb7fU +#define MSK3 0xbffaffffU +#define MSK4 0xbffffff6U +#define PARITY1 0x00000001U +#define PARITY2 0x00000000U +#define PARITY3 0x00000000U +#define PARITY4 0x13c9e684U + + +/* PARAMETERS FOR ALTIVEC */ +#if defined(__APPLE__) /* For OSX */ + #define ALTI_SL1 (vector unsigned int)(SL1, SL1, SL1, SL1) + #define ALTI_SR1 (vector unsigned int)(SR1, SR1, SR1, SR1) + #define ALTI_MSK (vector unsigned int)(MSK1, MSK2, MSK3, MSK4) + #define ALTI_MSK64 \ + (vector unsigned int)(MSK2, MSK1, MSK4, MSK3) + #define ALTI_SL2_PERM \ + (vector unsigned char)(1,2,3,23,5,6,7,0,9,10,11,4,13,14,15,8) + #define ALTI_SL2_PERM64 \ + (vector unsigned char)(1,2,3,4,5,6,7,31,9,10,11,12,13,14,15,0) + #define ALTI_SR2_PERM \ + (vector unsigned char)(7,0,1,2,11,4,5,6,15,8,9,10,17,12,13,14) + #define ALTI_SR2_PERM64 \ + (vector unsigned char)(15,0,1,2,3,4,5,6,17,8,9,10,11,12,13,14) +#else /* For OTHER OSs(Linux?) */ + #define ALTI_SL1 {SL1, SL1, SL1, SL1} + #define ALTI_SR1 {SR1, SR1, SR1, SR1} + #define ALTI_MSK {MSK1, MSK2, MSK3, MSK4} + #define ALTI_MSK64 {MSK2, MSK1, MSK4, MSK3} + #define ALTI_SL2_PERM {1,2,3,23,5,6,7,0,9,10,11,4,13,14,15,8} + #define ALTI_SL2_PERM64 {1,2,3,4,5,6,7,31,9,10,11,12,13,14,15,0} + #define ALTI_SR2_PERM {7,0,1,2,11,4,5,6,15,8,9,10,17,12,13,14} + #define ALTI_SR2_PERM64 {15,0,1,2,3,4,5,6,17,8,9,10,11,12,13,14} +#endif /* For OSX */ +#define IDSTR "SFMT-19937:122-18-1-11-1:dfffffef-ddfecb7f-bffaffff-bffffff6" + +#endif /* SFMT_PARAMS19937_H */ diff --git a/src/random/SFMT-params216091.h b/src/random/SFMT-params216091.h new file mode 100644 index 0000000..46c7303 --- /dev/null +++ b/src/random/SFMT-params216091.h @@ -0,0 +1,46 @@ +#ifndef SFMT_PARAMS216091_H +#define SFMT_PARAMS216091_H + +#define POS1 627 +#define SL1 11 +#define SL2 3 +#define SR1 10 +#define SR2 1 +#define MSK1 0xbff7bff7U +#define MSK2 0xbfffffffU +#define MSK3 0xbffffa7fU +#define MSK4 0xffddfbfbU +#define PARITY1 0xf8000001U +#define PARITY2 0x89e80709U +#define PARITY3 0x3bd2b64bU +#define PARITY4 0x0c64b1e4U + + +/* PARAMETERS FOR ALTIVEC */ +#if defined(__APPLE__) /* For OSX */ + #define ALTI_SL1 (vector unsigned int)(SL1, SL1, SL1, SL1) + #define ALTI_SR1 (vector unsigned int)(SR1, SR1, SR1, SR1) + #define ALTI_MSK (vector unsigned int)(MSK1, MSK2, MSK3, MSK4) + #define ALTI_MSK64 \ + (vector unsigned int)(MSK2, MSK1, MSK4, MSK3) + #define ALTI_SL2_PERM \ + (vector unsigned char)(3,21,21,21,7,0,1,2,11,4,5,6,15,8,9,10) + #define ALTI_SL2_PERM64 \ + (vector unsigned char)(3,4,5,6,7,29,29,29,11,12,13,14,15,0,1,2) + #define ALTI_SR2_PERM \ + (vector unsigned char)(7,0,1,2,11,4,5,6,15,8,9,10,17,12,13,14) + #define ALTI_SR2_PERM64 \ + (vector unsigned char)(15,0,1,2,3,4,5,6,17,8,9,10,11,12,13,14) +#else /* For OTHER OSs(Linux?) */ + #define ALTI_SL1 {SL1, SL1, SL1, SL1} + #define ALTI_SR1 {SR1, SR1, SR1, SR1} + #define ALTI_MSK {MSK1, MSK2, MSK3, MSK4} + #define ALTI_MSK64 {MSK2, MSK1, MSK4, MSK3} + #define ALTI_SL2_PERM {3,21,21,21,7,0,1,2,11,4,5,6,15,8,9,10} + #define ALTI_SL2_PERM64 {3,4,5,6,7,29,29,29,11,12,13,14,15,0,1,2} + #define ALTI_SR2_PERM {7,0,1,2,11,4,5,6,15,8,9,10,17,12,13,14} + #define ALTI_SR2_PERM64 {15,0,1,2,3,4,5,6,17,8,9,10,11,12,13,14} +#endif /* For OSX */ +#define IDSTR "SFMT-216091:627-11-3-10-1:bff7bff7-bfffffff-bffffa7f-ffddfbfb" + +#endif /* SFMT_PARAMS216091_H */ diff --git a/src/random/SFMT-params2281.h b/src/random/SFMT-params2281.h new file mode 100644 index 0000000..ee2ebdf --- /dev/null +++ b/src/random/SFMT-params2281.h @@ -0,0 +1,46 @@ +#ifndef SFMT_PARAMS2281_H +#define SFMT_PARAMS2281_H + +#define POS1 12 +#define SL1 19 +#define SL2 1 +#define SR1 5 +#define SR2 1 +#define MSK1 0xbff7ffbfU +#define MSK2 0xfdfffffeU +#define MSK3 0xf7ffef7fU +#define MSK4 0xf2f7cbbfU +#define PARITY1 0x00000001U +#define PARITY2 0x00000000U +#define PARITY3 0x00000000U +#define PARITY4 0x41dfa600U + + +/* PARAMETERS FOR ALTIVEC */ +#if defined(__APPLE__) /* For OSX */ + #define ALTI_SL1 (vector unsigned int)(SL1, SL1, SL1, SL1) + #define ALTI_SR1 (vector unsigned int)(SR1, SR1, SR1, SR1) + #define ALTI_MSK (vector unsigned int)(MSK1, MSK2, MSK3, MSK4) + #define ALTI_MSK64 \ + (vector unsigned int)(MSK2, MSK1, MSK4, MSK3) + #define ALTI_SL2_PERM \ + (vector unsigned char)(1,2,3,23,5,6,7,0,9,10,11,4,13,14,15,8) + #define ALTI_SL2_PERM64 \ + (vector unsigned char)(1,2,3,4,5,6,7,31,9,10,11,12,13,14,15,0) + #define ALTI_SR2_PERM \ + (vector unsigned char)(7,0,1,2,11,4,5,6,15,8,9,10,17,12,13,14) + #define ALTI_SR2_PERM64 \ + (vector unsigned char)(15,0,1,2,3,4,5,6,17,8,9,10,11,12,13,14) +#else /* For OTHER OSs(Linux?) */ + #define ALTI_SL1 {SL1, SL1, SL1, SL1} + #define ALTI_SR1 {SR1, SR1, SR1, SR1} + #define ALTI_MSK {MSK1, MSK2, MSK3, MSK4} + #define ALTI_MSK64 {MSK2, MSK1, MSK4, MSK3} + #define ALTI_SL2_PERM {1,2,3,23,5,6,7,0,9,10,11,4,13,14,15,8} + #define ALTI_SL2_PERM64 {1,2,3,4,5,6,7,31,9,10,11,12,13,14,15,0} + #define ALTI_SR2_PERM {7,0,1,2,11,4,5,6,15,8,9,10,17,12,13,14} + #define ALTI_SR2_PERM64 {15,0,1,2,3,4,5,6,17,8,9,10,11,12,13,14} +#endif /* For OSX */ +#define IDSTR "SFMT-2281:12-19-1-5-1:bff7ffbf-fdfffffe-f7ffef7f-f2f7cbbf" + +#endif /* SFMT_PARAMS2281_H */ diff --git a/src/random/SFMT-params4253.h b/src/random/SFMT-params4253.h new file mode 100644 index 0000000..f391a70 --- /dev/null +++ b/src/random/SFMT-params4253.h @@ -0,0 +1,46 @@ +#ifndef SFMT_PARAMS4253_H +#define SFMT_PARAMS4253_H + +#define POS1 17 +#define SL1 20 +#define SL2 1 +#define SR1 7 +#define SR2 1 +#define MSK1 0x9f7bffffU +#define MSK2 0x9fffff5fU +#define MSK3 0x3efffffbU +#define MSK4 0xfffff7bbU +#define PARITY1 0xa8000001U +#define PARITY2 0xaf5390a3U +#define PARITY3 0xb740b3f8U +#define PARITY4 0x6c11486dU + + +/* PARAMETERS FOR ALTIVEC */ +#if defined(__APPLE__) /* For OSX */ + #define ALTI_SL1 (vector unsigned int)(SL1, SL1, SL1, SL1) + #define ALTI_SR1 (vector unsigned int)(SR1, SR1, SR1, SR1) + #define ALTI_MSK (vector unsigned int)(MSK1, MSK2, MSK3, MSK4) + #define ALTI_MSK64 \ + (vector unsigned int)(MSK2, MSK1, MSK4, MSK3) + #define ALTI_SL2_PERM \ + (vector unsigned char)(1,2,3,23,5,6,7,0,9,10,11,4,13,14,15,8) + #define ALTI_SL2_PERM64 \ + (vector unsigned char)(1,2,3,4,5,6,7,31,9,10,11,12,13,14,15,0) + #define ALTI_SR2_PERM \ + (vector unsigned char)(7,0,1,2,11,4,5,6,15,8,9,10,17,12,13,14) + #define ALTI_SR2_PERM64 \ + (vector unsigned char)(15,0,1,2,3,4,5,6,17,8,9,10,11,12,13,14) +#else /* For OTHER OSs(Linux?) */ + #define ALTI_SL1 {SL1, SL1, SL1, SL1} + #define ALTI_SR1 {SR1, SR1, SR1, SR1} + #define ALTI_MSK {MSK1, MSK2, MSK3, MSK4} + #define ALTI_MSK64 {MSK2, MSK1, MSK4, MSK3} + #define ALTI_SL2_PERM {1,2,3,23,5,6,7,0,9,10,11,4,13,14,15,8} + #define ALTI_SL2_PERM64 {1,2,3,4,5,6,7,31,9,10,11,12,13,14,15,0} + #define ALTI_SR2_PERM {7,0,1,2,11,4,5,6,15,8,9,10,17,12,13,14} + #define ALTI_SR2_PERM64 {15,0,1,2,3,4,5,6,17,8,9,10,11,12,13,14} +#endif /* For OSX */ +#define IDSTR "SFMT-4253:17-20-1-7-1:9f7bffff-9fffff5f-3efffffb-fffff7bb" + +#endif /* SFMT_PARAMS4253_H */ diff --git a/src/random/SFMT-params44497.h b/src/random/SFMT-params44497.h new file mode 100644 index 0000000..ddef00d --- /dev/null +++ b/src/random/SFMT-params44497.h @@ -0,0 +1,46 @@ +#ifndef SFMT_PARAMS44497_H +#define SFMT_PARAMS44497_H + +#define POS1 330 +#define SL1 5 +#define SL2 3 +#define SR1 9 +#define SR2 3 +#define MSK1 0xeffffffbU +#define MSK2 0xdfbebfffU +#define MSK3 0xbfbf7befU +#define MSK4 0x9ffd7bffU +#define PARITY1 0x00000001U +#define PARITY2 0x00000000U +#define PARITY3 0xa3ac4000U +#define PARITY4 0xecc1327aU + + +/* PARAMETERS FOR ALTIVEC */ +#if defined(__APPLE__) /* For OSX */ + #define ALTI_SL1 (vector unsigned int)(SL1, SL1, SL1, SL1) + #define ALTI_SR1 (vector unsigned int)(SR1, SR1, SR1, SR1) + #define ALTI_MSK (vector unsigned int)(MSK1, MSK2, MSK3, MSK4) + #define ALTI_MSK64 \ + (vector unsigned int)(MSK2, MSK1, MSK4, MSK3) + #define ALTI_SL2_PERM \ + (vector unsigned char)(3,21,21,21,7,0,1,2,11,4,5,6,15,8,9,10) + #define ALTI_SL2_PERM64 \ + (vector unsigned char)(3,4,5,6,7,29,29,29,11,12,13,14,15,0,1,2) + #define ALTI_SR2_PERM \ + (vector unsigned char)(5,6,7,0,9,10,11,4,13,14,15,8,19,19,19,12) + #define ALTI_SR2_PERM64 \ + (vector unsigned char)(13,14,15,0,1,2,3,4,19,19,19,8,9,10,11,12) +#else /* For OTHER OSs(Linux?) */ + #define ALTI_SL1 {SL1, SL1, SL1, SL1} + #define ALTI_SR1 {SR1, SR1, SR1, SR1} + #define ALTI_MSK {MSK1, MSK2, MSK3, MSK4} + #define ALTI_MSK64 {MSK2, MSK1, MSK4, MSK3} + #define ALTI_SL2_PERM {3,21,21,21,7,0,1,2,11,4,5,6,15,8,9,10} + #define ALTI_SL2_PERM64 {3,4,5,6,7,29,29,29,11,12,13,14,15,0,1,2} + #define ALTI_SR2_PERM {5,6,7,0,9,10,11,4,13,14,15,8,19,19,19,12} + #define ALTI_SR2_PERM64 {13,14,15,0,1,2,3,4,19,19,19,8,9,10,11,12} +#endif /* For OSX */ +#define IDSTR "SFMT-44497:330-5-3-9-3:effffffb-dfbebfff-bfbf7bef-9ffd7bff" + +#endif /* SFMT_PARAMS44497_H */ diff --git a/src/random/SFMT-params607.h b/src/random/SFMT-params607.h new file mode 100644 index 0000000..fc2be6d --- /dev/null +++ b/src/random/SFMT-params607.h @@ -0,0 +1,46 @@ +#ifndef SFMT_PARAMS607_H +#define SFMT_PARAMS607_H + +#define POS1 2 +#define SL1 15 +#define SL2 3 +#define SR1 13 +#define SR2 3 +#define MSK1 0xfdff37ffU +#define MSK2 0xef7f3f7dU +#define MSK3 0xff777b7dU +#define MSK4 0x7ff7fb2fU +#define PARITY1 0x00000001U +#define PARITY2 0x00000000U +#define PARITY3 0x00000000U +#define PARITY4 0x5986f054U + + +/* PARAMETERS FOR ALTIVEC */ +#if defined(__APPLE__) /* For OSX */ + #define ALTI_SL1 (vector unsigned int)(SL1, SL1, SL1, SL1) + #define ALTI_SR1 (vector unsigned int)(SR1, SR1, SR1, SR1) + #define ALTI_MSK (vector unsigned int)(MSK1, MSK2, MSK3, MSK4) + #define ALTI_MSK64 \ + (vector unsigned int)(MSK2, MSK1, MSK4, MSK3) + #define ALTI_SL2_PERM \ + (vector unsigned char)(3,21,21,21,7,0,1,2,11,4,5,6,15,8,9,10) + #define ALTI_SL2_PERM64 \ + (vector unsigned char)(3,4,5,6,7,29,29,29,11,12,13,14,15,0,1,2) + #define ALTI_SR2_PERM \ + (vector unsigned char)(5,6,7,0,9,10,11,4,13,14,15,8,19,19,19,12) + #define ALTI_SR2_PERM64 \ + (vector unsigned char)(13,14,15,0,1,2,3,4,19,19,19,8,9,10,11,12) +#else /* For OTHER OSs(Linux?) */ + #define ALTI_SL1 {SL1, SL1, SL1, SL1} + #define ALTI_SR1 {SR1, SR1, SR1, SR1} + #define ALTI_MSK {MSK1, MSK2, MSK3, MSK4} + #define ALTI_MSK64 {MSK2, MSK1, MSK4, MSK3} + #define ALTI_SL2_PERM {3,21,21,21,7,0,1,2,11,4,5,6,15,8,9,10} + #define ALTI_SL2_PERM64 {3,4,5,6,7,29,29,29,11,12,13,14,15,0,1,2} + #define ALTI_SR2_PERM {5,6,7,0,9,10,11,4,13,14,15,8,19,19,19,12} + #define ALTI_SR2_PERM64 {13,14,15,0,1,2,3,4,19,19,19,8,9,10,11,12} +#endif /* For OSX */ +#define IDSTR "SFMT-607:2-15-3-13-3:fdff37ff-ef7f3f7d-ff777b7d-7ff7fb2f" + +#endif /* SFMT_PARAMS607_H */ diff --git a/src/random/SFMT-params86243.h b/src/random/SFMT-params86243.h new file mode 100644 index 0000000..3b52b76 --- /dev/null +++ b/src/random/SFMT-params86243.h @@ -0,0 +1,46 @@ +#ifndef SFMT_PARAMS86243_H +#define SFMT_PARAMS86243_H + +#define POS1 366 +#define SL1 6 +#define SL2 7 +#define SR1 19 +#define SR2 1 +#define MSK1 0xfdbffbffU +#define MSK2 0xbff7ff3fU +#define MSK3 0xfd77efffU +#define MSK4 0xbf9ff3ffU +#define PARITY1 0x00000001U +#define PARITY2 0x00000000U +#define PARITY3 0x00000000U +#define PARITY4 0xe9528d85U + + +/* PARAMETERS FOR ALTIVEC */ +#if defined(__APPLE__) /* For OSX */ + #define ALTI_SL1 (vector unsigned int)(SL1, SL1, SL1, SL1) + #define ALTI_SR1 (vector unsigned int)(SR1, SR1, SR1, SR1) + #define ALTI_MSK (vector unsigned int)(MSK1, MSK2, MSK3, MSK4) + #define ALTI_MSK64 \ + (vector unsigned int)(MSK2, MSK1, MSK4, MSK3) + #define ALTI_SL2_PERM \ + (vector unsigned char)(25,25,25,25,3,25,25,25,7,0,1,2,11,4,5,6) + #define ALTI_SL2_PERM64 \ + (vector unsigned char)(7,25,25,25,25,25,25,25,15,0,1,2,3,4,5,6) + #define ALTI_SR2_PERM \ + (vector unsigned char)(7,0,1,2,11,4,5,6,15,8,9,10,17,12,13,14) + #define ALTI_SR2_PERM64 \ + (vector unsigned char)(15,0,1,2,3,4,5,6,17,8,9,10,11,12,13,14) +#else /* For OTHER OSs(Linux?) */ + #define ALTI_SL1 {SL1, SL1, SL1, SL1} + #define ALTI_SR1 {SR1, SR1, SR1, SR1} + #define ALTI_MSK {MSK1, MSK2, MSK3, MSK4} + #define ALTI_MSK64 {MSK2, MSK1, MSK4, MSK3} + #define ALTI_SL2_PERM {25,25,25,25,3,25,25,25,7,0,1,2,11,4,5,6} + #define ALTI_SL2_PERM64 {7,25,25,25,25,25,25,25,15,0,1,2,3,4,5,6} + #define ALTI_SR2_PERM {7,0,1,2,11,4,5,6,15,8,9,10,17,12,13,14} + #define ALTI_SR2_PERM64 {15,0,1,2,3,4,5,6,17,8,9,10,11,12,13,14} +#endif /* For OSX */ +#define IDSTR "SFMT-86243:366-6-7-19-1:fdbffbff-bff7ff3f-fd77efff-bf9ff3ff" + +#endif /* SFMT_PARAMS86243_H */ diff --git a/src/random/SFMT-sse2.h b/src/random/SFMT-sse2.h new file mode 100644 index 0000000..4e91d9c --- /dev/null +++ b/src/random/SFMT-sse2.h @@ -0,0 +1,121 @@ +/** + * @file SFMT-sse2.h + * @brief SIMD oriented Fast Mersenne Twister(SFMT) for Intel SSE2 + * + * @author Mutsuo Saito (Hiroshima University) + * @author Makoto Matsumoto (Hiroshima University) + * + * @note We assume LITTLE ENDIAN in this file + * + * Copyright (C) 2006, 2007 Mutsuo Saito, Makoto Matsumoto and Hiroshima + * University. All rights reserved. + * + * The new BSD License is applied to this software, see LICENSE.txt + */ + +#ifndef SFMT_SSE2_H +#define SFMT_SSE2_H + +PRE_ALWAYS static __m128i mm_recursion(__m128i *a, __m128i *b, __m128i c, + __m128i d, __m128i mask) ALWAYSINLINE; + +/** + * This function represents the recursion formula. + * @param a a 128-bit part of the interal state array + * @param b a 128-bit part of the interal state array + * @param c a 128-bit part of the interal state array + * @param d a 128-bit part of the interal state array + * @param mask 128-bit mask + * @return output + */ +PRE_ALWAYS static __m128i mm_recursion(__m128i *a, __m128i *b, + __m128i c, __m128i d, __m128i mask) { + __m128i v, x, y, z; + + x = _mm_load_si128(a); + y = _mm_srli_epi32(*b, SR1); + z = _mm_srli_si128(c, SR2); + v = _mm_slli_epi32(d, SL1); + z = _mm_xor_si128(z, x); + z = _mm_xor_si128(z, v); + x = _mm_slli_si128(x, SL2); + y = _mm_and_si128(y, mask); + z = _mm_xor_si128(z, x); + z = _mm_xor_si128(z, y); + return z; +} + +/** + * This function fills the internal state array with pseudorandom + * integers. + */ +inline static void gen_rand_all(void) { + int i; + __m128i r, r1, r2, mask; + mask = _mm_set_epi32(MSK4, MSK3, MSK2, MSK1); + + r1 = _mm_load_si128(&sfmt[N - 2].si); + r2 = _mm_load_si128(&sfmt[N - 1].si); + for (i = 0; i < N - POS1; i++) { + r = mm_recursion(&sfmt[i].si, &sfmt[i + POS1].si, r1, r2, mask); + _mm_store_si128(&sfmt[i].si, r); + r1 = r2; + r2 = r; + } + for (; i < N; i++) { + r = mm_recursion(&sfmt[i].si, &sfmt[i + POS1 - N].si, r1, r2, mask); + _mm_store_si128(&sfmt[i].si, r); + r1 = r2; + r2 = r; + } +} + +/** + * This function fills the user-specified array with pseudorandom + * integers. + * + * @param array an 128-bit array to be filled by pseudorandom numbers. + * @param size number of 128-bit pesudorandom numbers to be generated. + */ +inline static void gen_rand_array(w128_t *array, int size) { + int i, j; + __m128i r, r1, r2, mask; + mask = _mm_set_epi32(MSK4, MSK3, MSK2, MSK1); + + r1 = _mm_load_si128(&sfmt[N - 2].si); + r2 = _mm_load_si128(&sfmt[N - 1].si); + for (i = 0; i < N - POS1; i++) { + r = mm_recursion(&sfmt[i].si, &sfmt[i + POS1].si, r1, r2, mask); + _mm_store_si128(&array[i].si, r); + r1 = r2; + r2 = r; + } + for (; i < N; i++) { + r = mm_recursion(&sfmt[i].si, &array[i + POS1 - N].si, r1, r2, mask); + _mm_store_si128(&array[i].si, r); + r1 = r2; + r2 = r; + } + /* main loop */ + for (; i < size - N; i++) { + r = mm_recursion(&array[i - N].si, &array[i + POS1 - N].si, r1, r2, + mask); + _mm_store_si128(&array[i].si, r); + r1 = r2; + r2 = r; + } + for (j = 0; j < 2 * N - size; j++) { + r = _mm_load_si128(&array[j + size - N].si); + _mm_store_si128(&sfmt[j].si, r); + } + for (; i < size; i++) { + r = mm_recursion(&array[i - N].si, &array[i + POS1 - N].si, r1, r2, + mask); + _mm_store_si128(&array[i].si, r); + _mm_store_si128(&sfmt[j++].si, r); + r1 = r2; + r2 = r; + } +} + +#endif diff --git a/src/random/SFMT.c b/src/random/SFMT.c new file mode 100644 index 0000000..5838dab --- /dev/null +++ b/src/random/SFMT.c @@ -0,0 +1,694 @@ +/** + * @file SFMT.c + * @brief SIMD oriented Fast Mersenne Twister(SFMT) + * + * @author Mutsuo Saito (Hiroshima University) + * @author Makoto Matsumoto (Hiroshima University) + * + * Copyright (C) 2006,2007 Mutsuo Saito, Makoto Matsumoto and Hiroshima + * University. All rights reserved. + * + * The new BSD License is applied to this software, see LICENSE.txt + */ +#include +#include +#include "SFMT.h" +#include "SFMT-params.h" + +#if defined(__BIG_ENDIAN__) && !defined(__amd64) && !defined(BIG_ENDIAN64) +#define BIG_ENDIAN64 1 +#endif +#if defined(HAVE_ALTIVEC) && !defined(BIG_ENDIAN64) +#define BIG_ENDIAN64 1 +#endif +#if defined(ONLY64) && !defined(BIG_ENDIAN64) + #if defined(__GNUC__) + #error "-DONLY64 must be specified with -DBIG_ENDIAN64" + #endif +#undef ONLY64 +#endif +/*------------------------------------------------------ + 128-bit SIMD data type for Altivec, SSE2 or standard C + ------------------------------------------------------*/ +#if defined(HAVE_ALTIVEC) + #if !defined(__APPLE__) + #include + #endif +/** 128-bit data structure */ +union W128_T { + vector unsigned int s; + uint32_t u[4]; +}; +/** 128-bit data type */ +typedef union W128_T w128_t; + +#elif defined(HAVE_SSE2) + #include + +/** 128-bit data structure */ +union W128_T { + __m128i si; + uint32_t u[4]; +}; +/** 128-bit data type */ +typedef union W128_T w128_t; + +#else + +/** 128-bit data structure */ +struct W128_T { + uint32_t u[4]; +}; +/** 128-bit data type */ +typedef struct W128_T w128_t; + +#endif + +/*-------------------------------------- + FILE GLOBAL VARIABLES + internal state, index counter and flag + --------------------------------------*/ +/** the 128-bit internal state array */ +static w128_t sfmt[N]; +/** the 32bit integer pointer to the 128-bit internal state array */ +static uint32_t *psfmt32 = &sfmt[0].u[0]; +#if !defined(BIG_ENDIAN64) || defined(ONLY64) +/** the 64bit integer pointer to the 128-bit internal state array */ +static uint64_t *psfmt64 = (uint64_t *)&sfmt[0].u[0]; +#endif +/** index counter to the 32-bit internal state array */ +static int idx; +/** a flag: it is 0 if and only if the internal state is not yet + * initialized. */ +static int initialized = 0; +/** a parity check vector which certificate the period of 2^{MEXP} */ +static uint32_t parity[4] = {PARITY1, PARITY2, PARITY3, PARITY4}; + +/*---------------- + STATIC FUNCTIONS + ----------------*/ +inline static int idxof(int i); +inline static void rshift128(w128_t *out, w128_t const *in, int shift); +inline static void lshift128(w128_t *out, w128_t const *in, int shift); +inline static void gen_rand_all(void); +inline static void gen_rand_array(w128_t *array, int size); +inline static uint32_t func1(uint32_t x); +inline static uint32_t func2(uint32_t x); +static void period_certification(void); +#if defined(BIG_ENDIAN64) && !defined(ONLY64) +inline static void swap(w128_t *array, int size); +#endif + +#if defined(HAVE_ALTIVEC) + #include "SFMT-alti.h" +#elif defined(HAVE_SSE2) + #include "SFMT-sse2.h" +#endif + +/** + * This function simulate a 64-bit index of LITTLE ENDIAN + * in BIG ENDIAN machine. + */ +#ifdef ONLY64 +inline static int idxof(int i) { + return i ^ 1; +} +#else +inline static int idxof(int i) { + return i; +} +#endif +/** + * This function simulates SIMD 128-bit right shift by the standard C. + * The 128-bit integer given in in is shifted by (shift * 8) bits. + * This function simulates the LITTLE ENDIAN SIMD. + * @param out the output of this function + * @param in the 128-bit data to be shifted + * @param shift the shift value + */ +#ifdef ONLY64 +inline static void rshift128(w128_t *out, w128_t const *in, int shift) { + uint64_t th, tl, oh, ol; + + th = ((uint64_t)in->u[2] << 32) | ((uint64_t)in->u[3]); + tl = ((uint64_t)in->u[0] << 32) | ((uint64_t)in->u[1]); + + oh = th >> (shift * 8); + ol = tl >> (shift * 8); + ol |= th << (64 - shift * 8); + out->u[0] = (uint32_t)(ol >> 32); + out->u[1] = (uint32_t)ol; + out->u[2] = (uint32_t)(oh >> 32); + out->u[3] = (uint32_t)oh; +} +#else +inline static void rshift128(w128_t *out, w128_t const *in, int shift) { + uint64_t th, tl, oh, ol; + + th = ((uint64_t)in->u[3] << 32) | ((uint64_t)in->u[2]); + tl = ((uint64_t)in->u[1] << 32) | ((uint64_t)in->u[0]); + + oh = th >> (shift * 8); + ol = tl >> (shift * 8); + ol |= th << (64 - shift * 8); + out->u[1] = (uint32_t)(ol >> 32); + out->u[0] = (uint32_t)ol; + out->u[3] = (uint32_t)(oh >> 32); + out->u[2] = (uint32_t)oh; +} +#endif +/** + * This function simulates SIMD 128-bit left shift by the standard C. + * The 128-bit integer given in in is shifted by (shift * 8) bits. + * This function simulates the LITTLE ENDIAN SIMD. + * @param out the output of this function + * @param in the 128-bit data to be shifted + * @param shift the shift value + */ +#ifdef ONLY64 +inline static void lshift128(w128_t *out, w128_t const *in, int shift) { + uint64_t th, tl, oh, ol; + + th = ((uint64_t)in->u[2] << 32) | ((uint64_t)in->u[3]); + tl = ((uint64_t)in->u[0] << 32) | ((uint64_t)in->u[1]); + + oh = th << (shift * 8); + ol = tl << (shift * 8); + oh |= tl >> (64 - shift * 8); + out->u[0] = (uint32_t)(ol >> 32); + out->u[1] = (uint32_t)ol; + out->u[2] = (uint32_t)(oh >> 32); + out->u[3] = (uint32_t)oh; +} +#else +inline static void lshift128(w128_t *out, w128_t const *in, int shift) { + uint64_t th, tl, oh, ol; + + th = ((uint64_t)in->u[3] << 32) | ((uint64_t)in->u[2]); + tl = ((uint64_t)in->u[1] << 32) | ((uint64_t)in->u[0]); + + oh = th << (shift * 8); + ol = tl << (shift * 8); + oh |= tl >> (64 - shift * 8); + out->u[1] = (uint32_t)(ol >> 32); + out->u[0] = (uint32_t)ol; + out->u[3] = (uint32_t)(oh >> 32); + out->u[2] = (uint32_t)oh; +} +#endif + +/** + * This function represents the recursion formula. + * @param r output + * @param a a 128-bit part of the internal state array + * @param b a 128-bit part of the internal state array + * @param c a 128-bit part of the internal state array + * @param d a 128-bit part of the internal state array + */ +#if (!defined(HAVE_ALTIVEC)) && (!defined(HAVE_SSE2)) +#ifdef ONLY64 +inline static void do_recursion(w128_t *r, w128_t *a, w128_t *b, w128_t *c, + w128_t *d) { + w128_t x; + w128_t y; + + lshift128(&x, a, SL2); + rshift128(&y, c, SR2); + r->u[0] = a->u[0] ^ x.u[0] ^ ((b->u[0] >> SR1) & MSK2) ^ y.u[0] + ^ (d->u[0] << SL1); + r->u[1] = a->u[1] ^ x.u[1] ^ ((b->u[1] >> SR1) & MSK1) ^ y.u[1] + ^ (d->u[1] << SL1); + r->u[2] = a->u[2] ^ x.u[2] ^ ((b->u[2] >> SR1) & MSK4) ^ y.u[2] + ^ (d->u[2] << SL1); + r->u[3] = a->u[3] ^ x.u[3] ^ ((b->u[3] >> SR1) & MSK3) ^ y.u[3] + ^ (d->u[3] << SL1); +} +#else +inline static void do_recursion(w128_t *r, w128_t *a, w128_t *b, w128_t *c, + w128_t *d) { + w128_t x; + w128_t y; + + lshift128(&x, a, SL2); + rshift128(&y, c, SR2); + r->u[0] = a->u[0] ^ x.u[0] ^ ((b->u[0] >> SR1) & MSK1) ^ y.u[0] + ^ (d->u[0] << SL1); + r->u[1] = a->u[1] ^ x.u[1] ^ ((b->u[1] >> SR1) & MSK2) ^ y.u[1] + ^ (d->u[1] << SL1); + r->u[2] = a->u[2] ^ x.u[2] ^ ((b->u[2] >> SR1) & MSK3) ^ y.u[2] + ^ (d->u[2] << SL1); + r->u[3] = a->u[3] ^ x.u[3] ^ ((b->u[3] >> SR1) & MSK4) ^ y.u[3] + ^ (d->u[3] << SL1); +} +#endif +#endif + +#if (!defined(HAVE_ALTIVEC)) && (!defined(HAVE_SSE2)) +/** + * This function fills the internal state array with pseudorandom + * integers. + */ +inline static void gen_rand_all(void) { + int i; + w128_t *r1, *r2; + + r1 = &sfmt[N - 2]; + r2 = &sfmt[N - 1]; + for (i = 0; i < N - POS1; i++) { + do_recursion(&sfmt[i], &sfmt[i], &sfmt[i + POS1], r1, r2); + r1 = r2; + r2 = &sfmt[i]; + } + for (; i < N; i++) { + do_recursion(&sfmt[i], &sfmt[i], &sfmt[i + POS1 - N], r1, r2); + r1 = r2; + r2 = &sfmt[i]; + } +} + +/** + * This function fills the user-specified array with pseudorandom + * integers. + * + * @param array an 128-bit array to be filled by pseudorandom numbers. + * @param size number of 128-bit pseudorandom numbers to be generated. + */ +inline static void gen_rand_array(w128_t *array, int size) { + int i, j; + w128_t *r1, *r2; + + r1 = &sfmt[N - 2]; + r2 = &sfmt[N - 1]; + for (i = 0; i < N - POS1; i++) { + do_recursion(&array[i], &sfmt[i], &sfmt[i + POS1], r1, r2); + r1 = r2; + r2 = &array[i]; + } + for (; i < N; i++) { + do_recursion(&array[i], &sfmt[i], &array[i + POS1 - N], r1, r2); + r1 = r2; + r2 = &array[i]; + } + for (; i < size - N; i++) { + do_recursion(&array[i], &array[i - N], &array[i + POS1 - N], r1, r2); + r1 = r2; + r2 = &array[i]; + } + for (j = 0; j < 2 * N - size; j++) { + sfmt[j] = array[j + size - N]; + } + for (; i < size; i++, j++) { + do_recursion(&array[i], &array[i - N], &array[i + POS1 - N], r1, r2); + r1 = r2; + r2 = &array[i]; + sfmt[j] = array[i]; + } +} +#endif + +#if defined(BIG_ENDIAN64) && !defined(ONLY64) && !defined(HAVE_ALTIVEC) +inline static void swap(w128_t *array, int size) { + int i; + uint32_t x, y; + + for (i = 0; i < size; i++) { + x = array[i].u[0]; + y = array[i].u[2]; + array[i].u[0] = array[i].u[1]; + array[i].u[2] = array[i].u[3]; + array[i].u[1] = x; + array[i].u[3] = y; + } +} +#endif +/** + * This function represents a function used in the initialization + * by init_by_array + * @param x 32-bit integer + * @return 32-bit integer + */ +static uint32_t func1(uint32_t x) { + return (x ^ (x >> 27)) * (uint32_t)1664525UL; +} + +/** + * This function represents a function used in the initialization + * by init_by_array + * @param x 32-bit integer + * @return 32-bit integer + */ +static uint32_t func2(uint32_t x) { + return (x ^ (x >> 27)) * (uint32_t)1566083941UL; +} + +/** + * This function certificate the period of 2^{MEXP} + */ +static void period_certification(void) { + int inner = 0; + int i, j; + uint32_t work; + + for (i = 0; i < 4; i++) + inner ^= psfmt32[idxof(i)] & parity[i]; + for (i = 16; i > 0; i >>= 1) + inner ^= inner >> i; + inner &= 1; + /* check OK */ + if (inner == 1) { + return; + } + /* check NG, and modification */ + for (i = 0; i < 4; i++) { + work = 1; + for (j = 0; j < 32; j++) { + if ((work & parity[i]) != 0) { + psfmt32[idxof(i)] ^= work; + return; + } + work = work << 1; + } + } +} + +/*---------------- + PUBLIC FUNCTIONS + ----------------*/ +/** + * This function returns the identification string. + * The string shows the word size, the Mersenne exponent, + * and all parameters of this generator. + */ +static INLINE const char *get_idstring(void) { + return IDSTR; +} + +/** + * This function returns the minimum size of array used for \b + * fill_array32() function. + * @return minimum size of array used for fill_array32() function. + */ +static INLINE int get_min_array_size32(void) { + return N32; +} + +/** + * This function returns the minimum size of array used for \b + * fill_array64() function. + * @return minimum size of array used for fill_array64() function. + */ +static INLINE int get_min_array_size64(void) { + return N64; +} + +#ifndef ONLY64 +/** + * This function generates and returns 32-bit pseudorandom number. + * init_gen_rand or init_by_array must be called before this function. + * @return 32-bit pseudorandom number + */ +static INLINE uint32_t gen_rand32(void) { + uint32_t r; + + assert(initialized); + if (idx >= N32) { + gen_rand_all(); + idx = 0; + } + r = psfmt32[idx++]; + return r; +} +#endif +/** + * This function generates and returns 64-bit pseudorandom number. + * init_gen_rand or init_by_array must be called before this function. + * The function gen_rand64 should not be called after gen_rand32, + * unless an initialization is again executed. + * @return 64-bit pseudorandom number + */ +static INLINE uint64_t gen_rand64(void) { +#if defined(BIG_ENDIAN64) && !defined(ONLY64) + uint32_t r1, r2; +#else + uint64_t r; +#endif + + assert(initialized); + assert(idx % 2 == 0); + + if (idx >= N32) { + gen_rand_all(); + idx = 0; + } +#if defined(BIG_ENDIAN64) && !defined(ONLY64) + r1 = psfmt32[idx]; + r2 = psfmt32[idx + 1]; + idx += 2; + return ((uint64_t)r2 << 32) | r1; +#else + r = psfmt64[idx / 2]; + idx += 2; + return r; +#endif +} + +#ifndef ONLY64 +/** + * This function generates pseudorandom 32-bit integers in the + * specified array[] by one call. The number of pseudorandom integers + * is specified by the argument size, which must be at least 624 and a + * multiple of four. The generation by this function is much faster + * than the following gen_rand function. + * + * For initialization, init_gen_rand or init_by_array must be called + * before the first call of this function. This function can not be + * used after calling gen_rand function, without initialization. + * + * @param array an array where pseudorandom 32-bit integers are filled + * by this function. The pointer to the array must be \b "aligned" + * (namely, must be a multiple of 16) in the SIMD version, since it + * refers to the address of a 128-bit integer. In the standard C + * version, the pointer is arbitrary. + * + * @param size the number of 32-bit pseudorandom integers to be + * generated. size must be a multiple of 4, and greater than or equal + * to (MEXP / 128 + 1) * 4. + * + * @note \b memalign or \b posix_memalign is available to get aligned + * memory. Mac OSX doesn't have these functions, but \b malloc of OSX + * returns the pointer to the aligned memory block. + */ +static INLINE void fill_array32(uint32_t *array, int size) { + assert(initialized); + assert(idx == N32); + assert(size % 4 == 0); + assert(size >= N32); + + gen_rand_array((w128_t *)array, size / 4); + idx = N32; +} +#endif + +/** + * This function generates pseudorandom 64-bit integers in the + * specified array[] by one call. The number of pseudorandom integers + * is specified by the argument size, which must be at least 312 and a + * multiple of two. The generation by this function is much faster + * than the following gen_rand function. + * + * For initialization, init_gen_rand or init_by_array must be called + * before the first call of this function. This function can not be + * used after calling gen_rand function, without initialization. + * + * @param array an array where pseudorandom 64-bit integers are filled + * by this function. The pointer to the array must be "aligned" + * (namely, must be a multiple of 16) in the SIMD version, since it + * refers to the address of a 128-bit integer. In the standard C + * version, the pointer is arbitrary. + * + * @param size the number of 64-bit pseudorandom integers to be + * generated. size must be a multiple of 2, and greater than or equal + * to (MEXP / 128 + 1) * 2 + * + * @note \b memalign or \b posix_memalign is available to get aligned + * memory. Mac OSX doesn't have these functions, but \b malloc of OSX + * returns the pointer to the aligned memory block. + */ +static INLINE void fill_array64(uint64_t *array, int size) { + assert(initialized); + assert(idx == N32); + assert(size % 2 == 0); + assert(size >= N64); + + gen_rand_array((w128_t *)array, size / 2); + idx = N32; + +#if defined(BIG_ENDIAN64) && !defined(ONLY64) + swap((w128_t *)array, size /2); +#endif +} + +/** + * This function initializes the internal state array with a 32-bit + * integer seed. + * + * @param seed a 32-bit integer used as the seed. + */ +static void init_gen_rand(uint32_t seed) { + int i; + + psfmt32[idxof(0)] = seed; + for (i = 1; i < N32; i++) { + psfmt32[idxof(i)] = 1812433253UL * (psfmt32[idxof(i - 1)] + ^ (psfmt32[idxof(i - 1)] >> 30)) + + i; + } + idx = N32; + period_certification(); + initialized = 1; +} + +/** + * This function initializes the internal state array, + * with an array of 32-bit integers used as the seeds + * @param init_key the array of 32-bit integers, used as a seed. + * @param key_length the length of init_key. + */ +static void init_by_array(uint32_t *init_key, int key_length) { + int i, j, count; + uint32_t r; + int lag; + int mid; + int size = N * 4; + + if (size >= 623) { + lag = 11; + } else if (size >= 68) { + lag = 7; + } else if (size >= 39) { + lag = 5; + } else { + lag = 3; + } + mid = (size - lag) / 2; + + memset(sfmt, 0x8b, sizeof(sfmt)); + if (key_length + 1 > N32) { + count = key_length + 1; + } else { + count = N32; + } + r = func1(psfmt32[idxof(0)] ^ psfmt32[idxof(mid)] + ^ psfmt32[idxof(N32 - 1)]); + psfmt32[idxof(mid)] += r; + r += key_length; + psfmt32[idxof(mid + lag)] += r; + psfmt32[idxof(0)] = r; + + count--; + for (i = 1, j = 0; (j < count) && (j < key_length); j++) { + r = func1(psfmt32[idxof(i)] ^ psfmt32[idxof((i + mid) % N32)] + ^ psfmt32[idxof((i + N32 - 1) % N32)]); + psfmt32[idxof((i + mid) % N32)] += r; + r += init_key[j] + i; + psfmt32[idxof((i + mid + lag) % N32)] += r; + psfmt32[idxof(i)] = r; + i = (i + 1) % N32; + } + for (; j < count; j++) { + r = func1(psfmt32[idxof(i)] ^ psfmt32[idxof((i + mid) % N32)] + ^ psfmt32[idxof((i + N32 - 1) % N32)]); + psfmt32[idxof((i + mid) % N32)] += r; + r += i; + psfmt32[idxof((i + mid + lag) % N32)] += r; + psfmt32[idxof(i)] = r; + i = (i + 1) % N32; + } + for (j = 0; j < N32; j++) { + r = func2(psfmt32[idxof(i)] + psfmt32[idxof((i + mid) % N32)] + + psfmt32[idxof((i + N32 - 1) % N32)]); + psfmt32[idxof((i + mid) % N32)] ^= r; + r -= i; + psfmt32[idxof((i + mid + lag) % N32)] ^= r; + psfmt32[idxof(i)] = r; + i = (i + 1) % N32; + } + + idx = N32; + period_certification(); + initialized = 1; +} + +/* These real versions are due to Isaku Wada */ +/** generates a random number on [0,1]-real-interval */ +inline static double to_real1(uint32_t v) +{ + return v * (1.0/4294967295.0); + /* divided by 2^32-1 */ +} + +/** generates a random number on [0,1]-real-interval */ +inline static double genrand_real1(void) +{ + return to_real1(gen_rand32()); +} + +/** generates a random number on [0,1)-real-interval */ +inline static double to_real2(uint32_t v) +{ + return v * (1.0/4294967296.0); + /* divided by 2^32 */ +} + +/** generates a random number on [0,1)-real-interval */ +inline static double genrand_real2(void) +{ + return to_real2(gen_rand32()); +} + +/** generates a random number on (0,1)-real-interval */ +inline static double to_real3(uint32_t v) +{ + return (((double)v) + 0.5)*(1.0/4294967296.0); + /* divided by 2^32 */ +} + +/** generates a random number on (0,1)-real-interval */ +inline static double genrand_real3(void) +{ + return to_real3(gen_rand32()); +} +/** These real versions are due to Isaku Wada */ + +/** generates a random number on [0,1) with 53-bit resolution*/ +inline static double to_res53(uint64_t v) +{ + return v * (1.0/18446744073709551616.0L); +} + +/** generates a random number on [0,1) with 53-bit resolution from two + * 32 bit integers */ +inline static double to_res53_mix(uint32_t x, uint32_t y) +{ + return to_res53(x | ((uint64_t)y << 32)); +} + +/** generates a random number on [0,1) with 53-bit resolution + */ +inline static double genrand_res53(void) +{ + return to_res53(gen_rand64()); +} + +/** generates a random number on [0,1) with 53-bit resolution + using 32bit integer. + */ +inline static double genrand_res53_mix(void) +{ + uint32_t x, y; + + x = gen_rand32(); + y = gen_rand32(); + return to_res53_mix(x, y); +} + diff --git a/src/random/SFMT.h b/src/random/SFMT.h new file mode 100644 index 0000000..e9e65a9 --- /dev/null +++ b/src/random/SFMT.h @@ -0,0 +1,87 @@ +/** + * @file SFMT.h + * + * @brief SIMD oriented Fast Mersenne Twister(SFMT) pseudorandom + * number generator + * + * @author Mutsuo Saito (Hiroshima University) + * @author Makoto Matsumoto (Hiroshima University) + * + * Copyright (C) 2006, 2007 Mutsuo Saito, Makoto Matsumoto and Hiroshima + * University. All rights reserved. + * + * The new BSD License is applied to this software. + * see LICENSE.txt + * + * @note We assume that your system has inttypes.h. If your system + * doesn't have inttypes.h, you have to typedef uint32_t and uint64_t, + * and you have to define PRIu64 and PRIx64 in this file as follows: + * @verbatim + typedef unsigned int uint32_t + typedef unsigned long long uint64_t + #define PRIu64 "llu" + #define PRIx64 "llx" +@endverbatim + * uint32_t must be exactly 32-bit unsigned integer type (no more, no + * less), and uint64_t must be exactly 64-bit unsigned integer type. + * PRIu64 and PRIx64 are used for printf function to print 64-bit + * unsigned int and 64-bit unsigned int in hexadecimal format. + */ + +#ifndef SFMT_H +#define SFMT_H + +#include + +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) + #include +#elif defined(_MSC_VER) || defined(__BORLANDC__) + typedef unsigned int uint32_t; + typedef unsigned __int64 uint64_t; + #define inline __inline +#else + #include + #if defined(__GNUC__) + #define inline __inline__ + #endif +#endif + +#ifndef PRIu64 + #if defined(_MSC_VER) || defined(__BORLANDC__) + #define PRIu64 "I64u" + #define PRIx64 "I64x" + #else + #define PRIu64 "llu" + #define PRIx64 "llx" + #endif +#endif + +#if defined(__GNUC__) +#define ALWAYSINLINE __attribute__((always_inline)) +#else +#define ALWAYSINLINE +#endif + +#if defined(_MSC_VER) + #if _MSC_VER >= 1200 + #define PRE_ALWAYS __forceinline + #else + #define PRE_ALWAYS inline + #endif +#else + #define PRE_ALWAYS inline +#endif + +/* these are not needed in public +uint32_t gen_rand32(void); +uint64_t gen_rand64(void); +void fill_array32(uint32_t *array, int size); +void fill_array64(uint64_t *array, int size); +void init_gen_rand(uint32_t seed); +void init_by_array(uint32_t *init_key, int key_length); +const char *get_idstring(void); +int get_min_array_size32(void); +int get_min_array_size64(void); +*/ + +#endif diff --git a/src/regexp.c b/src/regexp.c index f753382..1ef3832 100644 --- a/src/regexp.c +++ b/src/regexp.c @@ -45,13 +45,14 @@ #include #include "regexp.h" -#include "interpret.h" /* eval_cost */ #include "simulate.h" #include "xalloc.h" #ifdef DEBUG #include "main.h" #endif +#include "i-eval_cost.h" + /*-------------------------------------------------------------------------*/ /* The "internal use only" fields in regexp.h are present to pass info from @@ -215,7 +216,7 @@ static void reginsert (char op, unsigned char *opnd); static unsigned char *reg (Bool paren, int *flagp); static int regtry(regexp*, char *); -static int regmatch(unsigned char *); +static Bool regmatch(unsigned char *); static int regrepeat(unsigned char *); #ifdef DEBUG @@ -1162,9 +1163,7 @@ regmatch (unsigned char *prog) /* Couldn't or didn't -- back up. */ no--; reginput = save + no; - eval_cost ++; - total_evalcost++; - if (EVALUATION_TOO_LONG()) + if (add_eval_cost(1)) return RE_ERROR_BACKTRACK; } return RE_NOMATCH; diff --git a/src/settings/psyced b/src/settings/psyced index 41bdbe5..3905e77 100755 --- a/src/settings/psyced +++ b/src/settings/psyced @@ -63,6 +63,9 @@ enable_use_json=yes # compile expat xml & xmpp parser in, if available enable_use_expat=no +# compile iksemel parser in, if available +enable_use_iksemel=no + # compile DNS SRV support in, if available enable_use_srv=yes diff --git a/src/simul_efun.c b/src/simul_efun.c index d7b889a..1961807 100644 --- a/src/simul_efun.c +++ b/src/simul_efun.c @@ -200,6 +200,18 @@ assert_simul_efun_object (void) /* Get the name(s) of the simul_efun object. */ svp = apply_master(STR_GET_SEFUN, 0); + + /* If a simul_efun_object appears during the GET_SEFUN call, it + * might have been due to a recursive get_simul_efun() call which may + * have gotten an old backup copy. This can lead to hard-to-debug + * variable and function definition inconsistencies. + */ + if (simul_efun_object) + { + printf("%s simul_efun object appeared while asking for it.\n", time_stamp()); + return MY_TRUE; + } + if (svp == NULL) { printf("%s No simul_efun\n", time_stamp()); diff --git a/src/simulate.c b/src/simulate.c index 28f01d8..9da6f2c 100644 --- a/src/simulate.c +++ b/src/simulate.c @@ -44,7 +44,6 @@ #include "filestat.h" #include "gcollect.h" #include "heartbeat.h" -#include "interpret.h" #include "lex.h" #include "main.h" #include "mapping.h" @@ -72,6 +71,8 @@ #include "wiz_list.h" #include "xalloc.h" +#include "i-eval_cost.h" + #include "../mudlib/sys/debug_info.h" #include "../mudlib/sys/driver_hook.h" #include "../mudlib/sys/files.h" @@ -145,7 +146,7 @@ struct error_recovery_info toplevel_context }; rt_context_t * rt_context - = (rt_context_t *)&toplevel_context; + = (rt_context_t *)&toplevel_context.rt; /*-------------------------------------------------------------------------*/ @@ -392,9 +393,10 @@ catch_instruction ( int flags, uint offset * the global . */ svalue_t *sp; + svalue_t catch_value; /* Remove the catch context and get the old stackpointer setting */ - sp = pull_error_context(INTER_SP); + sp = pull_error_context(INTER_SP, &catch_value); /* beware of errors after set_this_object() */ current_object = csp->ob; @@ -407,7 +409,6 @@ catch_instruction ( int flags, uint offset /* Push the catch return value */ *(++sp) = catch_value; - catch_value.type = T_INVALID; *i_sp = (volatile svalue_t *)sp; @@ -436,8 +437,9 @@ catch_instruction ( int flags, uint offset if (max_eval_cost && eval_cost >= max_eval_cost) { - errorf("Not enough eval time left for catch(): required %ld, available %ld\n" - , (long)reserve_cost, (long)(max_eval_cost - eval_cost + reserve_cost) + errorf("Not enough eval time left for catch(): required %"PRId32 + ", available %"PRId32"\n", reserve_cost, + (max_eval_cost - eval_cost + reserve_cost) ); /* NOTREACHED */ return MY_TRUE; @@ -809,7 +811,12 @@ errorf (const char *fmt, ...) string_t * str = new_mstring(emsg_buf); if (NULL != str) - put_string(&catch_value, str); + { + svalue_t stmp; + + put_string(&stmp, str); + transfer_error_message(&stmp, rt); + } else { error_caught = MY_FALSE; @@ -933,7 +940,7 @@ errorf (const char *fmt, ...) if (curobj) { line_number = get_line_number_if_any(&file); - debug_message("%s program: %s, object: %s line %ld\n" + debug_message("%s program: %s, object: %s line %"PRIdMPINT"\n" , ts, get_txt(file), get_txt(curobj->name) , line_number); if (current_prog && num_error < 3) @@ -954,7 +961,7 @@ errorf (const char *fmt, ...) printf("%s error in function call: %s", ts, emsg_buf+1); if (curobj) { - printf("%s program: %s, object: %s line %ld\n" + printf("%s program: %s, object: %s line %"PRIdMPINT"\n" , ts, get_txt(file), get_txt(curobj->name) , line_number ); @@ -1191,7 +1198,7 @@ errorf (const char *fmt, ...) if (O_SET_INTERACTIVE(i, current_interactive) && i->noecho & NOECHO_STALE) { - set_noecho(i, 0, MY_FALSE); + set_noecho(i, 0, MY_FALSE, MY_FALSE); } } @@ -1285,7 +1292,7 @@ warnf (char *fmt, ...) if (curobj) { line_number = get_line_number_if_any(&file); - debug_message("%s program: %s, object: %s line %ld\n" + debug_message("%s program: %s, object: %s line %"PRIdMPINT"\n" , ts, get_txt(file), get_txt(curobj->name) , line_number); } @@ -1368,21 +1375,21 @@ parse_error (Bool warning, const char *error_file, int line, const char *what /*-------------------------------------------------------------------------*/ void -throw_error() +throw_error (svalue_t *v) -/* The second part of the efun throw(): the caller stored the message - * into catch_value, now our job is to do the proper longjmp. +/* The efun throw(). We have to save the message in the + * error context and then do the proper longjmp. is freed. */ { unroll_context_stack(); if (rt_context->type >= ERROR_RECOVERY_CATCH) { + transfer_error_message(v, rt_context); longjmp(((struct error_recovery_info *)rt_context)->con.text, 1); fatal("Throw_error failed!"); } - free_svalue(&catch_value); - catch_value.type = T_INVALID; + free_svalue(v); errorf("Throw with no catch.\n"); } /* throw_error() */ @@ -1452,8 +1459,8 @@ push_give_uid_error_context (object_t *ob) if (!ecp) { destruct(ob); - errorf("Out of memory (%lu bytes) for new object '%s' uids\n" - , (unsigned long) sizeof(*ecp), get_txt(ob->name)); + errorf("Out of memory (%zu bytes) for new object '%s' uids\n" + , sizeof(*ecp), get_txt(ob->name)); } ecp->new_object = ob; push_error_handler(give_uid_error_handler, &(ecp->head)); @@ -1751,8 +1758,8 @@ load_object_error(const char *msg, const char *name, namechain_t *chain) /* Make a local copy of the message so as not to leak memory */ buf = alloca(strbuf_length(&sbuf)+1); if (!buf) - errorf("Out of stack memory (%lu bytes)\n" - , (unsigned long) strlen(sbuf.buf)+1); + errorf("Out of stack memory (%zu bytes)\n" + , strlen(sbuf.buf)+1); strbuf_copy(&sbuf, buf); strbuf_free(&sbuf); @@ -1793,9 +1800,9 @@ load_object (const char *lname, Bool create_super, int depth int fd; object_t *ob; object_t *save_command_giver = command_giver; - int i; + long i; struct stat c_st; - int name_length; + size_t name_length; char *name; /* Copy of */ char *fname; /* Filename for */ program_t *prog; @@ -1806,6 +1813,16 @@ load_object (const char *lname, Bool create_super, int depth fatal("Improper filename '%s' passed to load_object()\n", lname); #endif + /* Empty lnames may lead to a driver crash in enter_object_hash() if there + * exists a file '.c' in the root of the mudlib. + */ + name_length = strlen(lname); + + if (name_length < 1) { + load_object_error("Illegal file to load (empty filename)", lname, chain); + /* NOTREACHED */ + } + /* It could be that the passed filename is one of an already loaded * object. In that case, simply return that object. */ @@ -1818,12 +1835,17 @@ load_object (const char *lname, Bool create_super, int depth /* We need two copies of : one to construct the filename in, * the second because lname might be a buffer which is deleted * during the compilation process. + * The memory is allocated in one chunk for both strings and an error + * handler is pushed on the stack (additionally is needed: memory for '/' + * and '\0’ (sizeof("/")) and '/', '\0', '.' and 'c' (sizeof("/.c"))). */ - name_length = strlen(lname); - name = alloca(name_length+2); - fname = alloca(name_length+4); - if (!name || !fname) - fatal("Stack overflow in load_object()"); + name = xalloc_with_error_handler(2 * name_length + sizeof("/") + + sizeof("/.c")); + fname = name + name_length + sizeof("/") + 1; + if (!name) + errorf("Out of memory (%zu bytes) in load_object() for temporary name " + "buffers.\n", 2*name_length + sizeof("/") + sizeof("/.c")); + if (!compat_mode) *name++ = '/'; /* Add and hide a leading '/' */ strcpy(name, lname); @@ -1854,6 +1876,7 @@ load_object (const char *lname, Bool create_super, int depth */ errorf("Out of memory: unswap object '%s'\n", get_txt(ob->name)); #endif + pop_stack(); /* free error handler */ return ob; } } @@ -1921,6 +1944,7 @@ load_object (const char *lname, Bool create_super, int depth ob->flags &= ~O_CLONE; ob->flags |= O_REPLACED; } + pop_stack(); /* free error handler */ return ob; } } @@ -1943,6 +1967,7 @@ load_object (const char *lname, Bool create_super, int depth ob->flags &= ~O_CLONE; ob->flags |= O_REPLACED; } + pop_stack(); /* free error handler */ return ob; } fname[name_length] = '.'; @@ -1974,6 +1999,7 @@ load_object (const char *lname, Bool create_super, int depth ob = lookup_object_hash_str((char *)name); if (ob) { + pop_stack(); /* free error handler */ return ob; } @@ -2105,7 +2131,7 @@ load_object (const char *lname, Bool create_super, int depth #ifdef CHECK_OBJECT_STAT if (check_object_stat) { - fprintf(stderr, "DEBUG: OSTAT: (%ld:%ld) load( %p '%s') name: %ld -> (%ld:%ld)\n" + fprintf(stderr, "DEBUG: OSTAT: (%ld:%ld) load( %p '%s') name: %zu -> (%ld:%ld)\n" , tot_alloc_object, tot_alloc_object_size, ob, ob->name ? get_txt(ob->name) : "" , mstrsize(ob->name) , tot_alloc_object @@ -2162,7 +2188,7 @@ load_object (const char *lname, Bool create_super, int depth { /* The master object is loaded with no current object */ current_object = NULL; - init_object_variables(ob); + init_object_variables(ob, NULL); reset_object(ob, create_super ? H_CREATE_SUPER : H_CREATE_OB); /* If the master inherits anything -Ugh- we have to have @@ -2173,7 +2199,7 @@ load_object (const char *lname, Bool create_super, int depth else { current_object = save_current; - init_object_variables(ob); + init_object_variables(ob, NULL); reset_object(ob, create_super ? H_CREATE_SUPER : H_CREATE_OB); } } @@ -2181,6 +2207,9 @@ load_object (const char *lname, Bool create_super, int depth if ( !(ob->flags & O_DESTRUCTED)) ob->flags |= O_WILL_CLEAN_UP; + /* free the error handler with the buffer for name and fname. */ + pop_stack(); + /* Restore the command giver */ command_giver = check_object(save_command_giver); @@ -2194,8 +2223,8 @@ load_object (const char *lname, Bool create_super, int depth #if 0 && defined(CHECK_OBJECT_REF) if (strchr(get_txt(ob->name), '#') == NULL) - printf("DEBUG: new_object(%p '%s') ref %ld flags %x\n" - , ob, get_txt(ob->name), (long)ob->ref, ob->flags); + printf("DEBUG: new_object(%p '%s') ref %"PRIdPINT" flags %x\n" + , ob, get_txt(ob->name), ob->ref, ob->flags); #endif return ob; } /* load_object() */ @@ -2358,7 +2387,7 @@ clone_object (string_t *str1) #ifdef CHECK_OBJECT_STAT if (check_object_stat) { - fprintf(stderr, "DEBUG: OSTAT: (%ld:%ld) clone( %p '%s') name: %ld -> (%ld:%ld)\n" + fprintf(stderr, "DEBUG: OSTAT: (%ld:%ld) clone( %p '%s') name: %zu -> (%ld:%ld)\n" , tot_alloc_object, tot_alloc_object_size, new_ob, new_ob->name ? get_txt(new_ob->name) : "" , mstrsize(new_ob->name) , tot_alloc_object @@ -2389,7 +2418,7 @@ clone_object (string_t *str1) push_ref_object(inter_sp, ob, "clone_object"); push_ref_string(inter_sp, new_ob->name); give_uid_to_object(new_ob, H_CLONE_UIDS, 2); - init_object_variables(new_ob); + init_object_variables(new_ob, ob); reset_object(new_ob, H_CREATE_CLONE); command_giver = check_object(save_command_giver); @@ -2513,7 +2542,7 @@ destruct_object (svalue_t *v) if (d_flag) { - debug_message("%s destruct_object: %s (ref %ld)\n" + debug_message("%s destruct_object: %s (ref %"PRIdPINT")\n" , time_stamp(), get_txt(ob->name), ob->ref); } @@ -2831,7 +2860,8 @@ check_object_shadow (object_t *ob, object_shadow_t *sh) if ((sh->flags & O_DESTRUCTED) != (ob->flags & O_DESTRUCTED) || sh->sent != ob->sent ) - fatal("DEBUG: Obj %p '%s': ref %ld, flags %x, sent %p; shadow ref %ld, flags %x, sent %p\n" + fatal("DEBUG: Obj %p '%s': ref %"PRIdPINT", flags %x, sent %p;" + "shadow ref %"PRIdPINT", flags %x, sent %p\n" , ob, get_txt(ob->name), ob->ref, ob->flags, ob->sent , sh->ref, sh->flags, sh->sent ); @@ -2874,7 +2904,7 @@ update_object_sent(object_t *obj, sentence_t *new_sent) break; if (sh == NULL) { - fatal("DEBUG: Obj %p '%s': ref %ld, flags %x, sent %p; no shadow found\n" + fatal("DEBUG: Obj %p '%s': ref %"PRIdPINT", flags %x, sent %p; no shadow found\n" , obj, get_txt(obj->name), obj->ref, obj->flags, obj->sent ); } @@ -2916,7 +2946,7 @@ remove_object (object_t *ob #endif if (d_flag > 1) { - debug_message("%s remove_object: object %s (ref %ld)\n" + debug_message("%s remove_object: object %s (ref %"PRIdPINT")\n" , time_stamp(), get_txt(ob->name), ob->ref); } @@ -3260,20 +3290,22 @@ status_parse (strbuf_t * sbuf, char * buff) if (!verbose) { #ifdef USE_ACTIONS - strbuf_addf(sbuf, "Actions:\t\t\t%8ld %9ld\n" + strbuf_addf(sbuf, "Actions:\t\t\t%8"PRIdPINT" %9"PRIdPINT"\n" , alloc_action_sent , alloc_action_sent * sizeof (action_t)); #endif #ifdef USE_SHADOWS - strbuf_addf(sbuf, "Shadows:\t\t\t%8ld %9ld\n" + strbuf_addf(sbuf, "Shadows:\t\t\t%8"PRIdPINT" %9"PRIdPINT"\n" , alloc_shadow_sent , alloc_shadow_sent * sizeof (shadow_t)); #endif - strbuf_addf(sbuf, "Objects:\t\t\t%8ld %9d (%lu destructed; %ld swapped: %ld Kbytes)\n" + strbuf_addf(sbuf, "Objects:\t\t\t%8ld %9ld (%ld destructed;" + " %"PRIdMPINT" swapped: %"PRIdMPINT" Kbytes)\n" , tot_alloc_object, tot_alloc_object_size - , num_destructed + , num_destructed , num_vb_swapped, total_vb_bytes_swapped / 1024); - strbuf_addf(sbuf, "Prog blocks:\t\t\t%8ld %9ld (%ld swapped: %ld Kbytes)\n" + strbuf_addf(sbuf, "Prog blocks:\t\t\t%8"PRIdMPINT" %9"PRIdMPINT + " (%"PRIdMPINT" swapped: %"PRIdMPINT" Kbytes)\n" , total_num_prog_blocks + num_swapped - num_unswapped , total_prog_block_size + total_bytes_swapped - total_bytes_unswapped @@ -3281,21 +3313,22 @@ status_parse (strbuf_t * sbuf, char * buff) , (total_bytes_swapped - total_bytes_unswapped) / 1024); strbuf_addf(sbuf, "Arrays:\t\t\t\t%8ld %9ld\n" , (long)num_arrays, total_array_size() ); - strbuf_addf(sbuf, "Mappings:\t\t\t%8ld %9ld (%ld hybrid, %ld hash)\n" + strbuf_addf(sbuf, "Mappings:\t\t\t%8"PRIdMPINT" %9"PRIdMPINT + " (%"PRIdMPINT" hybrid, %"PRIdMPINT" hash)\n" , num_mappings, total_mapping_size() , num_dirty_mappings, num_hash_mappings ); - strbuf_addf(sbuf, "Memory reserved:\t\t\t %9d\n", res); + strbuf_addf(sbuf, "Memory reserved:\t\t\t %9zu\n", res); } if (verbose) { /* TODO: Add these numbers to the debug_info statistics. */ strbuf_add(sbuf, "\nVM Execution:\n"); strbuf_add(sbuf, "-------------\n"); strbuf_addf(sbuf - , "Last: %7lu ticks, %3ld.%06ld s\n" - "Average: %7.0lf ticks, %10.6lf s\n" + , "Last: %10lu ticks, %3ld.%06ld s\n" + "Average: %10.0lf ticks, %10.6lf s\n" , last_total_evalcost - , last_eval_duration.tv_sec, last_eval_duration.tv_usec + , last_eval_duration.tv_sec, (long)last_eval_duration.tv_usec , stat_total_evalcost.weighted_avg , stat_eval_duration.weighted_avg / 1000000.0 ); @@ -3309,14 +3342,14 @@ status_parse (strbuf_t * sbuf, char * buff) strbuf_add(sbuf, "\nNetwork IO:\n"); strbuf_add(sbuf, "-----------\n"); strbuf_addf(sbuf - , "In: Packets: %7lu - Sum: %7lu - " + , "In: Packets: %10lu - Sum: %10lu - " "Average packet size: %7.2f\n" , inet_packets_in , inet_volume_in , inet_packets_in ? (float)inet_volume_in/(float)inet_packets_in : 0.0 ); strbuf_addf(sbuf - , "Out: Packets: %7lu - Sum: %7lu - " + , "Out: Packets: %10lu - Sum: %10lu - " "Average packet size: %7.2f\n" " Calls to add_message: %lu\n" , inet_packets @@ -3329,10 +3362,10 @@ status_parse (strbuf_t * sbuf, char * buff) strbuf_add(sbuf, "\nApply Cache:\n"); strbuf_add(sbuf, "------------\n"); strbuf_addf(sbuf - , "Calls to apply_low: %7lu\n" - "Cache hits: %7lu (%.2f%%)\n" - , (unsigned long)(apply_cache_hit+apply_cache_miss) - , (unsigned long)apply_cache_hit + , "Calls to apply_low: %10"PRIuPINT"\n" + "Cache hits: %10"PRIuPINT" (%.2f%%)\n" + , (apply_cache_hit+apply_cache_miss) + , apply_cache_hit , 100.*(float)apply_cache_hit/ (float)(apply_cache_hit+apply_cache_miss) ); #endif @@ -3349,70 +3382,70 @@ status_parse (strbuf_t * sbuf, char * buff) if (verbose) { #ifdef DEBUG - long count; + unsigned long count; object_t *ob; #endif strbuf_add(sbuf, "\nObject status:\n"); strbuf_add(sbuf, "--------------\n"); strbuf_addf(sbuf, "Objects total:\t\t\t %8ld\n" - , (long)tot_alloc_object); + , tot_alloc_object); #ifndef DEBUG - strbuf_addf(sbuf, "Objects in list:\t\t %8ld\n" - , (long)num_listed_objs); + strbuf_addf(sbuf, "Objects in list:\t\t %8lu\n" + , (unsigned long)num_listed_objs); strbuf_addf(sbuf, "Objects newly destructed:\t\t %8ld\n" - , (long)num_newly_destructed); + , num_newly_destructed); strbuf_addf(sbuf, "Objects destructed:\t\t %8ld\n" - , (long)num_destructed); + , num_destructed); #else for (count = 0, ob = obj_list; ob != NULL; ob = ob->next_all) count++; if (count != (long)num_listed_objs) { - debug_message("DEBUG: num_listed_objs mismatch: listed %ld, counted %ld\n" - , (long)num_listed_objs, count); - strbuf_addf(sbuf, "Objects in list:\t\t %8ld (counted %ld)\n" - , (long)num_listed_objs, count); + debug_message("DEBUG: num_listed_objs mismatch: listed %lu, counted %lu\n" + , (unsigned long)num_listed_objs, count); + strbuf_addf(sbuf, "Objects in list:\t\t %8lu (counted %lu)\n" + , (unsigned long)num_listed_objs, count); } else - strbuf_addf(sbuf, "Objects in list:\t\t %8ld\n" - , (long)num_listed_objs); + strbuf_addf(sbuf, "Objects in list:\t\t %8lu\n" + , (unsigned long)num_listed_objs); for (count = 0, ob = newly_destructed_objs; ob != NULL; ob = ob->next_all) count++; if (count != num_newly_destructed) { - debug_message("DEBUG: num_newly_destructed mismatch: listed %ld, counted %ld\n" - , (long)num_newly_destructed, count); - strbuf_addf(sbuf, "Objects newly destructed:\t\t %8ld (counted %ld)\n" - , (long)num_newly_destructed, count); + debug_message("DEBUG: num_newly_destructed mismatch: listed %ld, counted %lu\n" + , num_newly_destructed, count); + strbuf_addf(sbuf, "Objects newly destructed:\t\t %8ld (counted %lu)\n" + , num_newly_destructed, count); } else strbuf_addf(sbuf, "Objects newly destructed:\t %8ld\n" - , (long)num_newly_destructed); + , num_newly_destructed); for (count = 0, ob = destructed_objs; ob != NULL; ob = ob->next_all) count++; if (count != num_destructed) { - debug_message("DEBUG: num_destructed mismatch: listed %ld, counted %ld\n" - , (long)num_destructed, count); - strbuf_addf(sbuf, "Objects destructed:\t\t %8ld (counted %ld)\n" - , (long)num_destructed, count); + debug_message("DEBUG: num_destructed mismatch: listed %ld, counted %lu\n" + , num_destructed, count); + strbuf_addf(sbuf, "Objects destructed:\t\t %8ld (counted %lu)\n" + , num_destructed, count); } else strbuf_addf(sbuf, "Objects destructed:\t\t %8ld\n" - , (long)num_destructed); + , num_destructed); #endif strbuf_addf(sbuf, "Objects processed in last cycle: " - "%8ld (%5.1lf%% - avg. %5.1lf%%)\n" - , (long)num_last_processed + "%8lu (%5.1lf%% - avg. %5.1lf%%)\n" + , (unsigned long)num_last_processed , (float)num_last_processed / (float)num_listed_objs * 100.0 , 100.0 * relate_statistics(stat_last_processed, stat_in_list) ); #ifdef NEW_CLEANUP strbuf_addf(sbuf, "Objects data-cleaned in last cycle: " - "%5ld (%5.1lf%% - avg. %5.1lf : %5.1lf%%)\n" - , (long)num_last_data_cleaned + "%5lu (%5.1lf%% - avg. %5.1lf : %5.1lf%%)\n" + , (unsigned long)num_last_data_cleaned , (double)num_last_data_cleaned / (double)num_listed_objs * 100.0 , stat_last_data_cleaned.weighted_avg , 100.0 * relate_statistics(stat_last_data_cleaned, stat_in_list) @@ -3445,7 +3478,7 @@ status_parse (strbuf_t * sbuf, char * buff) #endif other += num_simul_efun * sizeof(function_t); other += interpreter_overhead(); - strbuf_addf(sbuf, "Other structures\t\t\t %9lu\n", other); + strbuf_addf(sbuf, "Other structures\t\t\t %9zu\n", other); tot += other; } tot += mb_status(sbuf, verbose); @@ -3454,7 +3487,7 @@ status_parse (strbuf_t * sbuf, char * buff) if (!verbose) { strbuf_add(sbuf, "\t\t\t\t\t ---------\n"); strbuf_add(sbuf, "Total:\t\t\t\t\t "); - strbuf_addf(sbuf, "%9d\n", tot); + strbuf_addf(sbuf, "%9zu\n", tot); } return MY_TRUE; } @@ -4446,12 +4479,12 @@ print_svalue (svalue_t *arg) else if (arg->type == T_OBJECT) add_message("OBJ(%s)", get_txt(arg->u.ob->name)); else if (arg->type == T_NUMBER) - add_message("%ld", arg->u.number); + add_message("%"PRIdPINT, arg->u.number); else if (arg->type == T_FLOAT) { char buff[120]; - sprintf(buff, "%g", READ_DOUBLE( arg ) ); + snprintf(buff, sizeof(buff), "%g", READ_DOUBLE( arg ) ); add_message(buff); } else if (arg->type == T_POINTER) @@ -4461,7 +4494,7 @@ print_svalue (svalue_t *arg) else if (arg->type == T_CLOSURE) add_message(""); else - add_message("", arg->type); + add_message("", arg->type); } /* print_svalue() */ /*=========================================================================*/ @@ -4899,7 +4932,7 @@ f_set_driver_hook (svalue_t *sp) if (n < 0 || n >= NUM_DRIVER_HOOKS) { - errorf("Bad hook number: %ld, expected 0..%ld\n" + errorf("Bad hook number: %"PRIdPINT", expected 0..%ld\n" , n, (long)NUM_DRIVER_HOOKS-1); /* NOTREACHED */ return sp; @@ -4930,9 +4963,9 @@ f_set_driver_hook (svalue_t *sp) && sp->u.number != RE_TRADITIONAL ) { - errorf("Bad value for hook %ld: got 0x%lx, expected RE_PCRE (0x%lx) " - "or RE_TRADITIONAL (0x%lx).\n" - , n, (long)sp->u.number + errorf("Bad value for hook %"PRIdPINT": got 0x%"PRIxPINT + ", expected RE_PCRE (0x%lx) or RE_TRADITIONAL (0x%lx).\n" + , n, sp->u.number , (long)RE_PCRE, (long)RE_TRADITIONAL ); break; @@ -4941,7 +4974,7 @@ f_set_driver_hook (svalue_t *sp) } else { - errorf("Bad value for hook %ld: got number, expected %s or 0.\n" + errorf("Bad value for hook %"PRIdPINT": got number, expected %s or 0.\n" , n , efun_arg_typename(hook_type_map[n])); break; @@ -4953,7 +4986,7 @@ f_set_driver_hook (svalue_t *sp) string_t *str; if ( !((1 << T_STRING) & hook_type_map[n]) ) - errorf("Bad value for hook %ld: got string, expected %s.\n" + errorf("Bad value for hook %"PRIdPINT": got string, expected %s.\n" , n , efun_arg_typename(hook_type_map[n])); @@ -4969,7 +5002,7 @@ f_set_driver_hook (svalue_t *sp) if (!sp->u.map->num_values || sp->u.map->ref != 1 /* add_to_mapping() could zero num_values */) { - errorf("Bad value for hook %ld: mapping is empty " + errorf("Bad value for hook %"PRIdPINT": mapping is empty " "or has other references.\n", n); return sp; } @@ -5009,7 +5042,7 @@ f_set_driver_hook (svalue_t *sp) } else if (!CLOSURE_IS_LFUN(sp->x.closure_type)) { - errorf("Bad value for hook %ld: unbound lambda or " + errorf("Bad value for hook %"PRIdPINT": unbound lambda or " "lfun closure expected.\n", n); } /* FALLTHROUGH */ @@ -5018,7 +5051,7 @@ f_set_driver_hook (svalue_t *sp) default_test: if ( !((1 << sp->type) & hook_type_map[n]) ) { - errorf("Bad value for hook %ld: got %s, expected %s.\n" + errorf("Bad value for hook %"PRIdPINT": got %s, expected %s.\n" , n, typename(sp->type), efun_arg_typename(hook_type_map[n])); break; /* flow control hint */ } @@ -5166,7 +5199,7 @@ set_single_limit ( struct limits_context_s * result } } else if (val != LIMIT_KEEP) - errorf("Illegal %s value: %ld\n", limitnames[limit], val); + errorf("Illegal %s value: %"PRIdPINT"\n", limitnames[limit], val); } } /* set_single_limit() */ @@ -5213,14 +5246,14 @@ extract_limits ( struct limits_context_s * result for (i = 0; i < num - 1; i += 2) { - int limit; + p_int limit; if (svp[i].type != T_NUMBER) errorf("Illegal limit value: got a %s, expected a number\n" , typename(svp[i].type)); - limit = (int)svp[i].u.number; + limit = svp[i].u.number; if (limit < 0 || limit >= LIMIT_MAX) - errorf("Illegal limit tag: %ld\n", (long)limit); + errorf("Illegal limit tag: %"PRIdPINT"\n", limit); set_single_limit(result, limit, svp+i+1); } @@ -5305,7 +5338,7 @@ v_limited (svalue_t * sp, int num_arg) limits.max_file = 0; limits.use_cost = 1; /* smallest we can do */ } - else if (argp[1].type == T_POINTER) + else if (argp[1].type == T_POINTER && VEC_SIZE(argp[1].u.vec) < INT_MAX) { extract_limits(&limits, argp[1].u.vec->item , (int)VEC_SIZE(argp[1].u.vec) @@ -5363,7 +5396,7 @@ v_limited (svalue_t * sp, int num_arg) /* Save the current runtime limits and set the new ones */ save_limits_context(&context); context.rt.last = rt_context; - rt_context = (rt_context_t *)&context; + rt_context = (rt_context_t *)&context.rt; max_eval_cost = limits.max_eval ? limits.max_eval + eval_cost : 0; /* Make sure that we get the requested amount of ticks, but remember @@ -5437,7 +5470,7 @@ v_set_limits (svalue_t * sp, int num_arg) argp = sp - num_arg + 1; - if (num_arg == 1 && argp->type == T_POINTER) + if (num_arg == 1 && argp->type == T_POINTER && VEC_SIZE(argp->u.vec) < INT_MAX) extract_limits(&limits, argp->u.vec->item, (int)VEC_SIZE(argp->u.vec) , MY_FALSE); else if (num_arg % 2 == 0) diff --git a/src/simulate.h b/src/simulate.h index 9e1014b..753a153 100644 --- a/src/simulate.h +++ b/src/simulate.h @@ -229,8 +229,8 @@ extern mp_int current_error_line_number; extern vector_t *uncaught_error_trace; extern vector_t *current_error_trace; -extern int game_is_being_shut_down; -extern int master_will_be_updated; +extern Bool game_is_being_shut_down; +extern Bool master_will_be_updated; /* --- Prototypes --- */ @@ -280,7 +280,7 @@ extern void dinfo_data_status(svalue_t * svp, int value); extern void warnf VARPROT((char *, ...), printf, 1, 2); extern void errorf VARPROT((const char *, ...), printf, 1, 2) NORETURN; extern void fatal VARPROT((const char *, ...), printf, 1, 2) NORETURN; -extern void throw_error(void); +extern void throw_error(svalue_t *v) NORETURN; extern char *limit_error_format(char *fixed_fmt, size_t fixed_fmt_len, const char *fmt); extern Bool legal_path(const char *path); extern Bool check_no_parentdirs(const char *path); diff --git a/src/slaballoc.c b/src/slaballoc.c index 26f7718..c6cd975 100644 --- a/src/slaballoc.c +++ b/src/slaballoc.c @@ -180,7 +180,7 @@ * Small free blocks: * * The M_SIZE field in fact holds the offset to the slab holding this - * block. + * block (this also holds true for the small allocated blocks). * * The first word of the user area holds the 'next' link of the free * list, which is NULL for the last block in the list. @@ -508,7 +508,7 @@ struct slabentry_s unsigned long numBlocks; /* Desired number of blocks per slab. */ }; -#define INIT_SLABENTRY { 0, 0, 0, 0, 0, 0, 0, 0, 0 } +#define INIT_SLABENTRY { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } #define INIT_SLABENTRY2 INIT_SLABENTRY, INIT_SLABENTRY #define INIT_SLABENTRY4 INIT_SLABENTRY2, INIT_SLABENTRY2 #define INIT_SLABENTRY8 INIT_SLABENTRY4, INIT_SLABENTRY4 @@ -569,20 +569,20 @@ static t_stat perm_alloc_stat = {0,0}; * figure is a subset of {small,large}_alloc_stat. */ -static long malloc_increment_size_calls = 0; +static unsigned long malloc_increment_size_calls = 0; /* Number of calls to malloc_increment_size(). */ -static long malloc_increment_size_success = 0; +static unsigned long malloc_increment_size_success = 0; /* Number of successfull calls to malloc_increment_size(). */ -static long malloc_increment_size_total = 0; +static unsigned long malloc_increment_size_total = 0; /* Total memory allocated through to malloc_increment_size(). */ #ifdef USE_AVL_FREELIST -static long num_avl_nodes = 0; +static unsigned long num_avl_nodes = 0; /* Number of nodes in the AVL tree managing the large free blocks. */ #endif /* USE_AVL_FREELIST */ @@ -729,7 +729,7 @@ mem_mark_permanent (POINTER p) if (q[-M_OVERHEAD] & M_GC_FREE) { q[-M_OVERHEAD] &= ~M_GC_FREE; - count_up(perm_alloc_stat, mem_block_total_size(q)); + count_up(&perm_alloc_stat, mem_block_total_size(q)); } } /* mem_mark_permanent() */ @@ -746,7 +746,7 @@ mem_mark_collectable (POINTER p) if (!(q[-M_OVERHEAD] & M_GC_FREE)) { q[-M_OVERHEAD] |= (M_REF|M_GC_FREE); - count_back(perm_alloc_stat, mem_block_total_size(q)); + count_back(&perm_alloc_stat, mem_block_total_size(q)); } } /* mem_mark_collectable() */ @@ -904,40 +904,42 @@ mem_dump_data (strbuf_t *sbuf) # define dump_stat(str,stat) strbuf_addf(sbuf, str,stat.counter,stat.size) strbuf_add(sbuf, "Type Count Space (bytes)\n"); - dump_stat("xallocs: %8u %10lu\n\n", xalloc_st); - dump_stat("sbrk requests: %8u %10lu (a)\n",sbrk_st); - dump_stat("large blocks: %8u %10lu (b)\n",l_alloc); + dump_stat("xallocs: %8lu %10lu\n\n", xalloc_st); + dump_stat("sbrk requests: %8lu %10lu (a)\n",sbrk_st); + dump_stat("large blocks: %8lu %10lu (b)\n",l_alloc); strbuf_addf(sbuf - , "large net avail: %10ld\n" + , "large net avail: %10lu\n" , l_alloc.size - l_alloc.counter * ML_OVERHEAD * SINT ); - dump_stat("large free blocks: %8u %10lu (c)\n",l_free); - dump_stat("large wasted: %8u %10lu (d)\n\n",l_wasted); - dump_stat("small slabs: %8u %10lu (e)\n",s_slab); - dump_stat("small blocks: %8u %10lu (f)\n",s_alloc); + dump_stat("large free blocks: %8lu %10lu (c)\n",l_free); + dump_stat("large wasted: %8lu %10lu (d)\n\n",l_wasted); + dump_stat("small slabs: %8lu %10lu (e)\n",s_slab); + dump_stat("small blocks: %8lu %10lu (f)\n",s_alloc); strbuf_addf(sbuf - , "small net avail: %10d\n" + , "small net avail: %10lu\n" , s_alloc.size - s_alloc.counter * M_OVERHEAD * SINT ); - dump_stat("small free blocks: %8u %10lu (g)\n",s_free); - dump_stat("small free slabs: %8u %10lu \n",s_free_slab); + dump_stat("small free blocks: %8lu %10lu (g)\n",s_free); + dump_stat("small free slabs: %8lu %10lu \n",s_free_slab); strbuf_addf(sbuf , "small overhead: %10lu (h)\n" , s_overhead ); - dump_stat("\npermanent blocks: %8u %10lu\n", perm_st); + dump_stat("\npermanent blocks: %8lu %10lu\n", perm_st); #ifdef SBRK_OK - dump_stat("clib allocations: %8u %10lu\n", clib_st); + dump_stat("clib allocations: %8lu %10lu\n", clib_st); #else strbuf_addf(sbuf, "clib allocations: n/a n/a\n"); #endif strbuf_add(sbuf, "\n"); #ifdef USE_AVL_FREELIST - strbuf_addf(sbuf, "AVL nodes: %8u -\n", num_avl_nodes); + strbuf_addf(sbuf, "AVL nodes: %8lu -\n", num_avl_nodes); strbuf_add(sbuf, "\n"); #endif /* USE_AVL_FREELIST */ +#undef dump_stat + strbuf_addf(sbuf, "malloc_increment_size: calls %lu success %lu total %lu\n\n", malloc_increment_size_calls, @@ -979,7 +981,7 @@ mem_dump_extdata (strbuf_t *sbuf) { #ifdef MALLOC_EXT_STATISTICS - int i; + unsigned int i; strbuf_add(sbuf, "Detailed Block Statistics:\n\n" @@ -1513,8 +1515,8 @@ free_slab (mslab_t * slab, int ix) { ulog2f("slaballoc: deallocate slab %x [%d]\n", slab, ix); slabtable[ix].numSlabs--; - count_back(small_slab_stat, SLAB_SIZE(slab, ix)); - count_back_n(small_free_stat, slabtable[ix].numBlocks, slab->size); + count_back(&small_slab_stat, SLAB_SIZE(slab, ix)); + count_back_n(&small_free_stat, slabtable[ix].numBlocks, slab->size); #ifdef MALLOC_EXT_STATISTICS extstats[SIZE_INDEX(slab->size)].cur_free -= slabtable[ix].numBlocks; extstats[EXTSTAT_SLABS].cur_free--; @@ -1591,7 +1593,7 @@ mem_alloc (size_t size) ulog2f(" %d bytes -> [%d]\n", size, ix); /* Update statistics */ - count_up(small_alloc_stat,size); + count_up(&small_alloc_stat,size); #ifdef MALLOC_EXT_STATISTICS extstats[SIZE_INDEX(size)].num_xalloc++; @@ -1612,7 +1614,7 @@ mem_alloc (size_t size) block = slab->freeList; slab->freeList = BLOCK_NEXT(slab->freeList); - count_back(small_free_stat, slab->size); + count_back(&small_free_stat, slab->size); #ifdef MALLOC_EXT_STATISTICS extstats[ix].cur_free--; @@ -1701,7 +1703,7 @@ mem_alloc (size_t size) } slabtable[ix].numFreeSlabs--; - count_back(small_slab_free_stat, SLAB_SIZE(slab, ix)); + count_back(&small_slab_free_stat, SLAB_SIZE(slab, ix)); #ifdef MALLOC_EXT_STATISTICS extstats[EXTSTAT_SLABS].cur_free--; #endif /* MALLOC_EXT_STATISTICS */ @@ -1733,8 +1735,8 @@ mem_alloc (size_t size) slab->size = size; slabtable[ix].numSlabs++; - count_up(small_slab_stat, slabSize); - count_up_n(small_free_stat, numObjects, size); + count_up(&small_slab_stat, slabSize); + count_up_n(&small_free_stat, numObjects, size); #ifdef MALLOC_EXT_STATISTICS extstats[ix].cur_free += numObjects; extstats[EXTSTAT_SLABS].num_xalloc++; @@ -1781,7 +1783,7 @@ mem_alloc (size_t size) MADVISE(block, orig_size); - count_back(small_free_stat, size); + count_back(&small_free_stat, size); #ifdef MALLOC_EXT_STATISTICS extstats[ix].cur_free--; #endif /* MALLOC_EXT_STATISTICS */ @@ -1870,7 +1872,7 @@ sfree (POINTER ptr) /* It's a small block: put it into the slab's free list */ slab = (mslab_t*)(block - (block[M_SIZE] & M_MASK)); - count_back(small_alloc_stat, slab->size); + count_back(&small_alloc_stat, slab->size); ix = SIZE_INDEX(slab->size); ulog4f("slaballoc: -> slab %x [%d], freelist %x, %d free\n" @@ -1886,31 +1888,28 @@ sfree (POINTER ptr) if (slab->magic == sfmagic[ix % NELEM(sfmagic)]) { in_malloc = 0; - fatal("mem_free: block %lx size %lu (user %lx) freed in free slab %lx\n" - , (unsigned long)block, (unsigned long)(ix * SINT) - , (unsigned long)ptr, (unsigned long) slab); + fatal("mem_free: block %p size %"PRIuPINT" (user %p) freed in free slab %p\n" + , block, (ix * SINT), ptr, slab); } if (slab->magic != samagic[ix % NELEM(samagic)]) { in_malloc = 0; - fatal("mem_free: block %p magic match failed for slab %lx: " - "size %lu, expected %lx, found %lx\n" - , block, (unsigned long)slab - , (unsigned long)(ix * SINT), samagic[ix], slab->magic); + fatal("mem_free: block %p magic match failed for slab %p: " + "size %"PRIuPINT", expected %"PRIuPINT", found %"PRIuPINT"\n" + , block, slab, (ix * SINT), (p_uint)samagic[ix], slab->magic); } if (block[M_MAGIC] == sfmagic[ix % NELEM(sfmagic)]) { in_malloc = 0; - fatal("mem_free: block %lx size %lu (user %lx) freed twice\n" - , (unsigned long)block, (unsigned long)(ix * SINT) - , (unsigned long)ptr); + fatal("mem_free: block %p size %"PRIuPINT" (user %p) freed twice\n" + , block, (ix * SINT), ptr); } if (block[M_MAGIC] != samagic[ix % NELEM(samagic)]) { in_malloc = 0; fatal("mem_free: block %p magic match failed: " - "size %lu, expected %lx, found %lx\n" - , block, (unsigned long)(ix * SINT), samagic[ix], block[M_MAGIC]); + "size %"PRIuPINT", expected %"PRIuPINT", found %"PRIuPINT"\n" + , block, (ix * SINT), (p_uint)samagic[ix], block[M_MAGIC]); } #endif @@ -1933,7 +1932,7 @@ sfree (POINTER ptr) slab->freeList = block; slab->numAllocated--; - count_up(small_free_stat, slab->size); + count_up(&small_free_stat, slab->size); /* If this slab is not the fresh slab, handle possible list movements. */ @@ -1993,7 +1992,7 @@ sfree (POINTER ptr) slabtable[ix].firstFree = slab; slabtable[ix].numFreeSlabs++; - count_up(small_slab_free_stat, SLAB_SIZE(slab, ix)); + count_up(&small_slab_free_stat, SLAB_SIZE(slab, ix)); #ifdef MALLOC_EXT_STATISTICS extstats[EXTSTAT_SLABS].cur_alloc--; extstats[EXTSTAT_SLABS].cur_free++; @@ -2131,6 +2130,7 @@ static struct free_block dummy = #ifdef USE_AVL_FREELIST , /* prev */ 0, /* next */ 0 #endif /* USE_AVL_FREELIST */ + , /* align_dummy */ 0 }; struct free_block dummy2 = @@ -2139,6 +2139,7 @@ static struct free_block dummy = #ifdef USE_AVL_FREELIST , /* prev */ 0, /* next */ 0 #endif /* USE_AVL_FREELIST */ + , /* align_dummy */ 0 }; static struct free_block *free_tree = &dummy2; @@ -2278,7 +2279,8 @@ check_free_block (void *m) if (!contains(free_tree, (struct free_block *)(p+size+T_OVERHEAD)) ) { in_malloc = 0; - fatal("not found\n"); + fatal("Memory at %p, size: %"PRIuPINT" (user: %p) was not found in the free_tree\n", + p, size, m); } } return 0; @@ -2305,16 +2307,14 @@ remove_from_free_list (word_t *ptr) { in_malloc = 0; fatal("remove_from_free_list: block %p, " - "magic match failed: expected %lx, " - "found %lx\n" - , ptr - , (unsigned long)LFMAGIC - , (unsigned long)ptr[M_MAGIC] + "magic match failed: expected %"PRIuPINT", " + "found %"PRIuPINT"\n" + , ptr, (p_uint)LFMAGIC, ptr[M_MAGIC] ); } #endif p = (struct free_block *)(ptr+M_OVERHEAD); - count_back(large_free_stat, p->size); + count_back(&large_free_stat, p->size); #ifdef MALLOC_EXT_STATISTICS extstats[EXTSTAT_LARGE].cur_free--; #endif /* MALLOC_EXT_STATISTICS */ @@ -2338,7 +2338,9 @@ remove_from_free_list (word_t *ptr) #ifdef DEBUG if (p->parent) { - fatal("(remove_from_free_list) Node %p (size %ld) is the AVL tree root, but has a parent\n", p, (long)p->size); + fatal("(remove_from_free_list) Node %p (size %"PRIuPINT + ") is the AVL tree root, but has a parent\n", + p, p->size); } #endif free_tree = p->next; @@ -2348,7 +2350,9 @@ remove_from_free_list (word_t *ptr) #ifdef DEBUG if (!p->parent) { - fatal("(remove_from_free_list) Node %p (size %ld) has neither a parent nor is it the AVL tree root.\n", p, (long)p->size); + fatal("(remove_from_free_list) Node %p (size %"PRIuPINT + ") has neither a parent nor is it the AVL tree root.\n", + p, p->size); } #endif if (p->parent->left == p) @@ -2703,7 +2707,7 @@ add_to_free_list (word_t *ptr) * register choice */ r = (struct free_block *)(ptr+M_OVERHEAD); - count_up(large_free_stat, size); + count_up(&large_free_stat, size); #ifdef MALLOC_EXT_STATISTICS extstats[EXTSTAT_LARGE].cur_free++; extstat_update_max(extstats+EXTSTAT_LARGE); @@ -3344,7 +3348,7 @@ found_fit: { mark_block(ptr+size); *(ptr+size) &= ~M_GC_FREE; /* Hands off, GC! */ - count_up(large_wasted_stat, (*(ptr+size) & M_MASK) * SINT); + count_up(&large_wasted_stat, (*(ptr+size) & M_MASK) * SINT); } else # endif @@ -3360,7 +3364,7 @@ found_fit: /* The block at ptr is all ours */ mark_block(ptr); - count_up(large_alloc_stat, size); + count_up(&large_alloc_stat, size); #ifdef MALLOC_EXT_STATISTICS extstats[EXTSTAT_LARGE].num_xalloc++; extstats[EXTSTAT_LARGE].cur_alloc++; @@ -3388,7 +3392,7 @@ large_free (char *ptr) p = (word_t *) ptr; p -= M_OVERHEAD; size = p[M_LSIZE]; - count_back(large_alloc_stat, size); + count_back(&large_alloc_stat, size); #ifdef MALLOC_EXT_STATISTICS extstats[EXTSTAT_LARGE].num_xfree++; extstats[EXTSTAT_LARGE].cur_alloc--; @@ -3398,19 +3402,17 @@ large_free (char *ptr) if (p[M_MAGIC] == LFMAGIC) { in_malloc = 0; - fatal("large_free: block %lx size %lu, (user %lx) freed twice\n" - , (unsigned long)p, (unsigned long)(size * SINT) - , (unsigned long)ptr); + fatal("large_free: block %p size %"PRIuPINT", (user %p) freed twice\n" + , p, (size * SINT), ptr); } if (p[M_MAGIC] != LAMAGIC) { in_malloc = 0; - fatal("large_free(%p): block %p magic match failed: size %lu, " - "expected %lx, found %lx\n" - , ptr, p - , (unsigned long)(size * SINT) - , (unsigned long)LAMAGIC - , (unsigned long)p[M_MAGIC] + fatal("large_free(%p): block %p magic match failed: size %"PRIuPINT", " + "expected %"PRIuPINT", found %"PRIuPINT"\n" + , ptr, p, (size * SINT) + , (p_uint)LAMAGIC + , p[M_MAGIC] ); } #endif @@ -3460,7 +3462,7 @@ esbrk (word_t size, size_t * pExtra) } *heap_start = 2; *(heap_start+1) = PREV_BLOCK | M_MASK; - count_up(large_wasted_stat, 2*SINT); + count_up(&large_wasted_stat, 2*SINT); assert_stack_gap(); } @@ -3468,7 +3470,7 @@ esbrk (word_t size, size_t * pExtra) if ((int)brk((char *)heap_end + size) == -1) return NULL; - count_up(sbrk_stat, size); + count_up(&sbrk_stat, size); heap_end = (word_t*)((char *)heap_end + size); heap_end[-1] = THIS_BLOCK | M_MASK; heap_end[-2] = M_MASK; @@ -3535,7 +3537,7 @@ esbrk (word_t size, size_t * pExtra) /* We can join with the existing heap */ p[overhead] &= ~PREV_BLOCK; overlap = SINT; - count_back(large_wasted_stat, overlap); + count_back(&large_wasted_stat, overlap); } else { @@ -3559,7 +3561,7 @@ esbrk (word_t size, size_t * pExtra) heap_end = (word_t *)(block + size); block -= overhead; overlap = overhead * SINT; - count_back(large_wasted_stat, overlap); + count_back(&large_wasted_stat, overlap); } else { @@ -3594,7 +3596,7 @@ esbrk (word_t size, size_t * pExtra) /* Our block directly follows the one we found */ block -= overhead; overlap += overhead * SINT; - count_back(large_wasted_stat, overhead * SINT); + count_back(&large_wasted_stat, overhead * SINT); } else { @@ -3619,7 +3621,7 @@ esbrk (word_t size, size_t * pExtra) /* Our block directly preceedes the next one */ *(next+1) &= ~PREV_BLOCK; overlap += overhead * SINT; - count_back(large_wasted_stat, overhead * SINT); + count_back(&large_wasted_stat, overhead * SINT); } else { @@ -3630,8 +3632,8 @@ esbrk (word_t size, size_t * pExtra) } } - count_up(sbrk_stat, size); - count_up(large_wasted_stat, overhead * SINT); + count_up(&sbrk_stat, size); + count_up(&large_wasted_stat, overhead * SINT); *pExtra = overlap; return block + SINT; @@ -3681,7 +3683,7 @@ mem_increment_size (void *vp, size_t size) start[M_LSIZE] += wsize; malloc_increment_size_success++; malloc_increment_size_total += (start2 - start) - M_OVERHEAD; - count_add(large_alloc_stat, wsize); + count_add(&large_alloc_stat, wsize); return start2+M_LSIZE; } @@ -3699,7 +3701,7 @@ mem_increment_size (void *vp, size_t size) start[M_LSIZE] += wsize; malloc_increment_size_success++; malloc_increment_size_total += (start2 - start) - M_OVERHEAD; - count_add(large_alloc_stat, wsize); + count_add(&large_alloc_stat, wsize); return start2+M_LSIZE; } @@ -3859,8 +3861,8 @@ mem_clear_ref_flags (void) if (p + *p > heap_end) { in_malloc = 0; - fatal("pointer larger than brk: %p + %lx = %p > %p\n" - , p, *p, p + *p , last); + fatal("pointer larger than brk: %p + %"PRIuPINT" = %p > %p\n" + , p, (p_uint)(*p), p + *p , last); } p += *p; } @@ -3950,7 +3952,7 @@ mem_free_unrefed_slab_memory ( const char * tag { /* Unref'd small blocks are definitely lost */ success++; - count_back(xalloc_stat, slab->size - (T_OVERHEAD * SINT)); + count_back(&xalloc_stat, slab->size - (T_OVERHEAD * SINT)); dprintf2(gcollect_outfd, "freeing small block 0x%x (user 0x%x)" , (p_uint)p, (p_uint)(p+M_OVERHEAD)); #ifdef MALLOC_TRACE @@ -4007,7 +4009,7 @@ mem_free_unrefed_memory (void) word_t size2, flags2; success++; - count_back(xalloc_stat, mem_block_size(p+ML_OVERHEAD)); + count_back(&xalloc_stat, mem_block_size(p+ML_OVERHEAD)); #if defined(MALLOC_TRACE) || defined(MALLOC_LPC_TRACE) dprintf1(gcollect_outfd, "freeing large block 0x%x", (p_uint)p); #endif @@ -4319,7 +4321,7 @@ mem_consolidate (Bool force) while (NULL != (slab = slabtable[ix].firstFree)) { slabtable[ix].firstFree = slab->next; - count_back(small_slab_free_stat, SLAB_SIZE(slab, ix)); + count_back(&small_slab_free_stat, SLAB_SIZE(slab, ix)); free_slab(slab, ix); } slabtable[ix].numFreeSlabs = 0; @@ -4343,7 +4345,7 @@ mem_consolidate (Bool force) else slabtable[ix].firstFree = NULL; slabtable[ix].numFreeSlabs--; - count_back(small_slab_free_stat, SLAB_SIZE(slab, ix)); + count_back(&small_slab_free_stat, SLAB_SIZE(slab, ix)); free_slab(slab, ix); } #ifdef DEBUG_MALLOC_ALLOCS diff --git a/src/smalloc.c b/src/smalloc.c index ec75f81..cef73e5 100644 --- a/src/smalloc.c +++ b/src/smalloc.c @@ -695,7 +695,7 @@ mem_mark_permanent (POINTER p) if (q[-M_OVERHEAD] & M_GC_FREE) { q[-M_OVERHEAD] &= ~M_GC_FREE; - count_up(perm_alloc_stat, mem_block_total_size(q)); + count_up(&perm_alloc_stat, mem_block_total_size(q)); } } /* mem_mark_permanent() */ @@ -712,7 +712,7 @@ mem_mark_collectable (POINTER p) if (!(q[-M_OVERHEAD] & M_GC_FREE)) { q[-M_OVERHEAD] |= (M_REF|M_GC_FREE); - count_back(perm_alloc_stat, mem_block_total_size(q)); + count_back(&perm_alloc_stat, mem_block_total_size(q)); } } /* mem_mark_collectable() */ @@ -832,6 +832,8 @@ mem_dump_data (strbuf_t *sbuf) strbuf_add(sbuf, "\n"); #endif /* USE_AVL_FREELIST */ +#undef dump_stat + strbuf_addf(sbuf, "malloc_increment_size: calls %lu success %lu total %lu\n\n", malloc_increment_size_calls, @@ -1111,7 +1113,7 @@ UNLINK_SMALL_FREE (word_t * block) next[M_PLINK(next[M_SIZE] & M_MASK)] = (word_t)prev | flag; prev[M_LINK] = (word_t) next; } - count_back(small_free_stat, bsize * SINT); + count_back(&small_free_stat, bsize * SINT); } /* UNLINK_SMALL_FREE() */ @@ -1159,7 +1161,7 @@ void MAKE_SMALL_FREE (word_t *block, word_t bsize) block[M_PLINK(bsize)-1] = bsize; sfltable[ix] = block; - count_up(small_free_stat, bsize * SINT); + count_up(&small_free_stat, bsize * SINT); #ifdef MALLOC_CHECK block[M_MAGIC] = sfmagic[SIZE_MOD_INDEX(bsize * SINT, sfmagic)]; @@ -1482,7 +1484,7 @@ mem_alloc (size_t size) size = (size+M_OVERHEAD*SINT+SINT-1) & ~(SINT-1); /* Update statistics */ - count_up(small_alloc_stat,size); + count_up(&small_alloc_stat,size); #ifdef MALLOC_EXT_STATISTICS extstats[SIZE_INDEX(size)].num_xalloc++; extstats[SIZE_INDEX(size)].cur_alloc++; @@ -1558,7 +1560,7 @@ mem_alloc (size_t size) /* Just modify the size and move the .prev pointer * and size field. */ - count_back(small_free_stat, bsize * SINT); + count_back(&small_free_stat, bsize * SINT); this[M_SIZE] &= (PREV_BLOCK|M_DEFRAG); this[M_SIZE] |= rsize | (THIS_BLOCK|M_REF); @@ -1569,7 +1571,7 @@ mem_alloc (size_t size) this[M_MAGIC] = sfmagic[SIZE_MOD_INDEX(rsize*SINT, sfmagic)]; #endif - count_up(small_free_stat, rsize * SINT); + count_up(&small_free_stat, rsize * SINT); } /* Split off the allocated small block from the end @@ -1717,8 +1719,8 @@ mem_alloc (size_t size) *new_chunk = (word_t)last_small_chunk; last_small_chunk = new_chunk++; - count_up(small_chunk_stat, new_chunk[-ML_OVERHEAD-1] * SINT); - count_up(small_chunk_wasted, SINT*(M_OVERHEAD+1)); + count_up(&small_chunk_stat, new_chunk[-ML_OVERHEAD-1] * SINT); + count_up(&small_chunk_wasted, SINT*(M_OVERHEAD+1)); small_chunk_size = SMALL_CHUNK_SIZE; @@ -1782,7 +1784,7 @@ sfree (POINTER ptr) /* It's a small block: put it back into the free list */ - count_back(small_alloc_stat, bsize * SINT); + count_back(&small_alloc_stat, bsize * SINT); i -= SMALL_BLOCK_MIN + T_OVERHEAD; #ifdef MALLOC_EXT_STATISTICS @@ -2104,7 +2106,7 @@ remove_from_free_list (word_t *ptr) } #endif p = (struct free_block *)(ptr+M_OVERHEAD); - count_back(large_free_stat, p->size); + count_back(&large_free_stat, p->size); #ifdef MALLOC_EXT_STATISTICS extstats[SMALL_BLOCK_NUM+1].cur_free--; #endif /* MALLOC_EXT_STATISTICS */ @@ -2493,7 +2495,7 @@ add_to_free_list (word_t *ptr) * register choice */ r = (struct free_block *)(ptr+M_OVERHEAD); - count_up(large_free_stat, size); + count_up(&large_free_stat, size); #ifdef MALLOC_EXT_STATISTICS extstats[SMALL_BLOCK_NUM+1].cur_free++; extstat_update_max(extstats+SMALL_BLOCK_NUM+1); @@ -3131,7 +3133,7 @@ found_fit: { mark_block(ptr+size); *(ptr+size) &= ~M_GC_FREE; /* Hands off, GC! */ - count_up(large_wasted_stat, (*(ptr+size) & M_MASK) * SINT); + count_up(&large_wasted_stat, (*(ptr+size) & M_MASK) * SINT); } else # endif @@ -3147,7 +3149,7 @@ found_fit: /* The block at ptr is all ours */ mark_block(ptr); - count_up(large_alloc_stat, size); + count_up(&large_alloc_stat, size); #ifdef MALLOC_EXT_STATISTICS extstats[SMALL_BLOCK_NUM+1].num_xalloc++; extstats[SMALL_BLOCK_NUM+1].cur_alloc++; @@ -3175,7 +3177,7 @@ large_free (char *ptr) p = (word_t *) ptr; p -= M_OVERHEAD; size = p[M_LSIZE]; - count_back(large_alloc_stat, size); + count_back(&large_alloc_stat, size); #ifdef MALLOC_EXT_STATISTICS extstats[SMALL_BLOCK_NUM+1].num_xfree++; extstats[SMALL_BLOCK_NUM+1].cur_alloc--; @@ -3247,7 +3249,7 @@ esbrk (word_t size, size_t * pExtra) } *heap_start = 2; *(heap_start+1) = PREV_BLOCK | M_MASK; - count_up(large_wasted_stat, 2*SINT); + count_up(&large_wasted_stat, 2*SINT); assert_stack_gap(); } @@ -3255,7 +3257,7 @@ esbrk (word_t size, size_t * pExtra) if ((int)brk((char *)heap_end + size) == -1) return NULL; - count_up(sbrk_stat, size); + count_up(&sbrk_stat, size); heap_end = (word_t*)((char *)heap_end + size); heap_end[-1] = THIS_BLOCK | M_MASK; heap_end[-2] = M_MASK; @@ -3321,7 +3323,7 @@ esbrk (word_t size, size_t * pExtra) /* We can join with the existing heap */ p[overhead] &= ~PREV_BLOCK; overlap = SINT; - count_back(large_wasted_stat, overlap); + count_back(&large_wasted_stat, overlap); } else { @@ -3345,7 +3347,7 @@ esbrk (word_t size, size_t * pExtra) heap_end = (word_t *)(block + size); block -= overhead; overlap = overhead * SINT; - count_back(large_wasted_stat, overlap); + count_back(&large_wasted_stat, overlap); } else { @@ -3380,7 +3382,7 @@ esbrk (word_t size, size_t * pExtra) /* Our block directly follows the one we found */ block -= overhead; overlap += overhead * SINT; - count_back(large_wasted_stat, overhead * SINT); + count_back(&large_wasted_stat, overhead * SINT); } else { @@ -3405,7 +3407,7 @@ esbrk (word_t size, size_t * pExtra) /* Our block directly preceedes the next one */ *(next+1) &= ~PREV_BLOCK; overlap += overhead * SINT; - count_back(large_wasted_stat, overhead * SINT); + count_back(&large_wasted_stat, overhead * SINT); } else { @@ -3416,8 +3418,8 @@ esbrk (word_t size, size_t * pExtra) } } - count_up(sbrk_stat, size); - count_up(large_wasted_stat, overhead * SINT); + count_up(&sbrk_stat, size); + count_up(&large_wasted_stat, overhead * SINT); *pExtra = overlap; return block + SINT; @@ -3477,7 +3479,7 @@ mem_increment_size (void *vp, size_t size) malloc_increment_size_success++; malloc_increment_size_total += (start2 - start) - M_OVERHEAD; - count_add(small_alloc_stat, wsize * SINT); + count_add(&small_alloc_stat, wsize * SINT); #ifdef MALLOC_EXT_STATISTICS extstats[SIZE_INDEX(old_size * SINT)].cur_alloc--; @@ -3504,7 +3506,7 @@ mem_increment_size (void *vp, size_t size) malloc_increment_size_success++; malloc_increment_size_total += (start2 - start) - M_OVERHEAD; - count_add(small_alloc_stat, wsize * SINT); + count_add(&small_alloc_stat, wsize * SINT); #ifdef MALLOC_EXT_STATISTICS extstats[SIZE_INDEX(old_size * SINT)].cur_alloc--; @@ -3536,7 +3538,7 @@ mem_increment_size (void *vp, size_t size) start[M_LSIZE] += wsize; malloc_increment_size_success++; malloc_increment_size_total += (start2 - start) - M_OVERHEAD; - count_add(large_alloc_stat, wsize); + count_add(&large_alloc_stat, wsize); return start2+M_LSIZE; } @@ -3554,7 +3556,7 @@ mem_increment_size (void *vp, size_t size) start[M_LSIZE] += wsize; malloc_increment_size_success++; malloc_increment_size_total += (start2 - start) - M_OVERHEAD; - count_add(large_alloc_stat, wsize); + count_add(&large_alloc_stat, wsize); return start2+M_LSIZE; } @@ -3745,7 +3747,7 @@ mem_free_unrefed_memory (void) word_t size2, flags2; success++; - count_back(xalloc_stat, mem_block_size(p+ML_OVERHEAD)); + count_back(&xalloc_stat, mem_block_size(p+ML_OVERHEAD)); #if defined(MALLOC_TRACE) || defined(MALLOC_LPC_TRACE) dprintf1(gcollect_outfd, "freeing large block 0x%x", (p_uint)p); #endif @@ -3793,7 +3795,7 @@ mem_free_unrefed_memory (void) { /* Unref'd small blocks are definitely lost */ success++; - count_back(xalloc_stat, mem_block_size(q+M_OVERHEAD)); + count_back(&xalloc_stat, mem_block_size(q+M_OVERHEAD)); dprintf2(gcollect_outfd, "freeing small block 0x%x (user 0x%x)" , (p_uint)q, (p_uint)(q+M_OVERHEAD)); #ifdef MALLOC_TRACE @@ -3993,8 +3995,8 @@ mem_consolidate (Bool force) UNLINK_SMALL_FREE(this+1); large_free((char *)this); - count_back(small_chunk_stat, chunk_size * SINT); - count_back(small_chunk_wasted, SINT*(M_OVERHEAD+2)); + count_back(&small_chunk_stat, chunk_size * SINT); + count_back(&small_chunk_wasted, SINT*(M_OVERHEAD+2)); this = next; } diff --git a/src/sprintf.c b/src/sprintf.c index 5ef643b..11452e1 100644 --- a/src/sprintf.c +++ b/src/sprintf.c @@ -133,30 +133,32 @@ typedef unsigned int format_info; -#define INFO_T 0xF -#define INFO_T_ERROR 0x1 -#define INFO_T_NULL 0x2 -#define INFO_T_LPC 0x3 -#define INFO_T_QLPC 0x4 -#define INFO_T_STRING 0x5 -#define INFO_T_INT 0x6 -#define INFO_T_FLOAT 0x7 +enum format_info_t { + INFO_T = 0xF, + INFO_T_ERROR = 0x1, + INFO_T_NULL = 0x2, + INFO_T_LPC = 0x3, + INFO_T_QLPC = 0x4, + INFO_T_STRING = 0x5, + INFO_T_INT = 0x6, + INFO_T_FLOAT = 0x7, -#define INFO_A 0x30 /* Right alignment */ -#define INFO_A_CENTRE 0x10 -#define INFO_A_LEFT 0x20 -#define INFO_A_JUSTIFY 0x30 + INFO_A = 0x30, /* Right alignment */ + INFO_A_CENTRE = 0x10, + INFO_A_LEFT = 0x20, + INFO_A_JUSTIFY = 0x30, -#define INFO_PP 0xC0 -#define INFO_PP_SPACE 0x40 -#define INFO_PP_PLUS 0x80 + INFO_PP = 0xC0, + INFO_PP_SPACE = 0x40, + INFO_PP_PLUS = 0x80, -#define INFO_ARRAY 0x100 -#define INFO_COLS 0x200 -#define INFO_TABLE 0x400 + INFO_ARRAY = 0x100, + INFO_COLS = 0x200, + INFO_TABLE = 0x400, -#define INFO_PS_ZERO 0x800 -#define INFO_PS_KEEP 0x1000 + INFO_PS_ZERO = 0x800, + INFO_PS_KEEP = 0x1000, +}; /*-------------------------------------------------------------------------*/ @@ -166,27 +168,28 @@ typedef unsigned int format_info; /* The error handling */ +enum format_err { + ERR_ID_NUMBER = 0xFFFF, /* Mask for the error number */ + ERR_ARGUMENT = 0xFFFF0000, /* Mask for the arg number */ + + ERR_BUFF_OVERFLOW = 0x1, /* buffer overflowed */ + ERR_TO_FEW_ARGS = 0x2, /* more arguments spec'ed than passed */ + ERR_INVALID_STAR = 0x3, /* invalid arg to * */ + ERR_PREC_EXPECTED = 0x4, /* expected precision not found */ + ERR_INVALID_FORMAT_STR = 0x5, /* error in format string */ + ERR_INCORRECT_ARG = 0x6, /* invalid arg to %[idcxXs] */ + ERR_CST_REQUIRES_FS = 0x7, /* field size not given for c/t */ + ERR_UNDEFINED_TYPE = 0x8, /* undefined type found */ + ERR_QUOTE_EXPECTED = 0x9, /* expected ' not found */ + ERR_UNEXPECTED_EOS = 0xA, /* fs terminated unexpectedly */ + ERR_NULL_PS = 0xB, /* pad string is null */ + ERR_ARRAY_EXPECTED = 0xC, /* array expected */ + ERR_NOMEM = 0xD, /* Out of memory */ + ERR_SIZE_OVERFLOW = 0xE, /* Fieldsize/precision numeric overflow */ +}; + #define ERROR(x) (longjmp(st->error_jmp, (x))) -#define ERR_ID_NUMBER 0xFFFF /* Mask for the error number */ -#define ERR_ARGUMENT 0xFFFF0000 /* Mask for the arg number */ - -#define ERR_BUFF_OVERFLOW 0x1 /* buffer overflowed */ -#define ERR_TO_FEW_ARGS 0x2 /* more arguments spec'ed than passed */ -#define ERR_INVALID_STAR 0x3 /* invalid arg to * */ -#define ERR_PREC_EXPECTED 0x4 /* expected precision not found */ -#define ERR_INVALID_FORMAT_STR 0x5 /* error in format string */ -#define ERR_INCORRECT_ARG 0x6 /* invalid arg to %[idcxXs] */ -#define ERR_CST_REQUIRES_FS 0x7 /* field size not given for c/t */ -#define ERR_UNDEFINED_TYPE 0x8 /* undefined type found */ -#define ERR_QUOTE_EXPECTED 0x9 /* expected ' not found */ -#define ERR_UNEXPECTED_EOS 0xA /* fs terminated unexpectedly */ -#define ERR_NULL_PS 0xB /* pad string is null */ -#define ERR_ARRAY_EXPECTED 0xC /* array expected */ -#define ERR_NOMEM 0xD /* Out of memory */ -#define ERR_SIZE_OVERFLOW 0xE /* Fieldsize/precision numeric overflow */ - - #define ERROR1(e,a) ERROR((e) | (a)<<16) #define EXTRACT_ERR_ARGUMENT(i) ((i)>>16) @@ -326,60 +329,60 @@ static sprintf_buffer_t *svalue_to_string(fmt_state_t * , int, Bool, Bool, Bool, Bool); /*-------------------------------------------------------------------------*/ -/* Macros */ -#define ADD_CHAR(x) {\ - if (st->bpos >= BUFF_SIZE) ERROR(ERR_BUFF_OVERFLOW); \ - if (x == '\n' && st->sppos != -1) st->bpos = st->sppos; \ - st->sppos = -1; \ - st->buff[st->bpos++] = x;\ +/* static helper functions */ +static inline void ADD_CHAR(fmt_state_t *st, char x) { + if (st->bpos >= BUFF_SIZE) ERROR(ERR_BUFF_OVERFLOW); + if (x == '\n' && st->sppos != -1) st->bpos = st->sppos; + st->sppos = -1; + st->buff[st->bpos++] = x; } /* Add character to the buffer. */ /*-------------------------------------------------------------------------*/ -#define ADD_STRN(s, n) { \ - if (st->bpos + n > BUFF_SIZE) ERROR(ERR_BUFF_OVERFLOW); \ - if (n >= 1 && (s)[0] == '\n' && st->sppos != -1) st->bpos = st->sppos; \ - st->sppos = -1; \ - memcpy(st->buff+st->bpos, (s), n);\ - st->bpos += n; \ +static inline void ADD_STRN(fmt_state_t *st, const char *s, size_t n) { + if (st->bpos + n > BUFF_SIZE) ERROR(ERR_BUFF_OVERFLOW); + if (n >= 1 && s[0] == '\n' && st->sppos != -1) st->bpos = st->sppos; + st->sppos = -1; + memcpy(st->buff+st->bpos, s, n); + st->bpos += n; } /* Add the characters from to the buffer. */ /*-------------------------------------------------------------------------*/ -#define ADD_CHARN(c, n) { \ - /* n must not be negative! */ \ - if (st->bpos + n > BUFF_SIZE) ERROR(ERR_BUFF_OVERFLOW); \ - if (n >= 1 && c == '\n' && st->sppos != -1) st->bpos = st->sppos; \ - st->sppos = -1; \ - memset(st->buff+st->bpos, c, n); \ - st->bpos += n; \ +static inline void ADD_CHARN(fmt_state_t *st, char c, size_t n) { + /* n must not be negative! */ + if (st->bpos + n > BUFF_SIZE) ERROR(ERR_BUFF_OVERFLOW); + if (n >= 1 && c == '\n' && st->sppos != -1) st->bpos = st->sppos; + st->sppos = -1; + memset(st->buff+st->bpos, c, n); + st->bpos += n; } /* Add character -times to the buffer. */ /*-------------------------------------------------------------------------*/ -#define ADD_PADDING(pad, N) { \ - int n = (N); \ -\ - if (!pad[1]) { \ - ADD_CHARN(*pad, n) \ - } else { \ - int l; \ -\ - l = strlen(pad); \ - for (i=0; --n >= 0; ) { \ - if (pad[i] == '\\') \ - i++; \ - ADD_CHAR(pad[i]); \ - if (++i == l) \ - i = 0; \ - } \ - } \ +static inline void ADD_PADDING(fmt_state_t *st, const char *pad, size_t N) { + int n = N; + + if (!pad[1]) { + ADD_CHARN(st, *pad, n); + } else { + int i, l; + + l = strlen(pad); + for (i=0; --n >= 0; ) { + if (pad[i] == '\\') + i++; + ADD_CHAR(st, pad[i]); + if (++i == l) + i = 0; + } + } } /* Add the padding string to the buffer, repeatedly if necessary, @@ -455,7 +458,7 @@ stradd (fmt_state_t *st, sprintf_buffer_t **buffer, char *add) /*-------------------------------------------------------------------------*/ static void -numadd (fmt_state_t *st, sprintf_buffer_t **buffer, int num) +numadd (fmt_state_t *st, sprintf_buffer_t **buffer, p_int num) /* Add the ber to the . */ @@ -1082,7 +1085,6 @@ add_justified ( fmt_state_t *st */ { - int i; size_t sppos; int num_words; /* Number of words in the input */ int num_chars; /* Number of non-space characters in the input */ @@ -1149,7 +1151,7 @@ add_justified ( fmt_state_t *st for (mark = pos ; pos < len && str[pos] != ' '; pos++) NOOP; /* Add the word */ - ADD_STRN(str+mark, pos - mark); + ADD_STRN(st, str+mark, pos - mark); num_words--; if (pos >= len || num_words < 1) @@ -1169,7 +1171,7 @@ add_justified ( fmt_state_t *st else /* Randomly add one space */ padlength = min_spaces + (int)random_number(2); sppos = st->bpos; - ADD_PADDING(" ", padlength); + ADD_PADDING(st, " ", padlength); st->sppos = sppos; num_spaces -= padlength; @@ -1189,7 +1191,6 @@ add_aligned ( fmt_state_t *st */ { - int i; size_t sppos; Bool is_space_pad; @@ -1206,10 +1207,10 @@ add_aligned ( fmt_state_t *st case INFO_A_JUSTIFY: case INFO_A_LEFT: /* Also called for the last line of a justified block */ - ADD_STRN(str, len) + ADD_STRN(st, str, len); if (is_space_pad) sppos = st->bpos; - ADD_PADDING(pad, fs - len) + ADD_PADDING(st, pad, fs - len); if (is_space_pad) st->sppos = sppos; break; @@ -1217,16 +1218,16 @@ add_aligned ( fmt_state_t *st case INFO_A_CENTRE: if (finfo & INFO_PS_ZERO) { - ADD_PADDING("0", (fs - len + 1) >> 1) + ADD_PADDING(st, "0", (fs - len + 1) >> 1); } else { - ADD_PADDING(pad, (fs - len + 1) >> 1) + ADD_PADDING(st, pad, (fs - len + 1) >> 1); } - ADD_STRN(str, len) + ADD_STRN(st, str, len); if (is_space_pad) sppos = st->bpos; - ADD_PADDING(pad, (fs - len) >> 1) + ADD_PADDING(st, pad, (fs - len) >> 1); if (is_space_pad) st->sppos = sppos; break; @@ -1236,13 +1237,13 @@ add_aligned ( fmt_state_t *st */ if (finfo & INFO_PS_ZERO) { - ADD_PADDING("0", fs - len) + ADD_PADDING(st, "0", fs - len); } else { - ADD_PADDING(pad, fs - len) + ADD_PADDING(st, pad, fs - len); } - ADD_STRN(str, len) + ADD_STRN(st, str, len); } } } /* add_aligned() */ @@ -1403,7 +1404,7 @@ add_table (fmt_state_t *st, cst **table) for (; i < TAB->nocols; i++) { /* TAB->size is not negative. */ - ADD_CHARN(' ', done) + ADD_CHARN(st, ' ', done); } } @@ -1454,7 +1455,7 @@ static char buff[BUFF_SIZE]; /* For error messages */ char format_char; /* format type */ unsigned int nelemno; /* next offset into array */ unsigned int fpos; /* position in format_str */ - unsigned long fs; /* field size */ + p_uint fs; /* field size */ int pres; /* precision */ unsigned int err_num; /* error code */ char *pad; /* fs pad string */ @@ -1661,11 +1662,11 @@ static char buff[BUFF_SIZE]; /* For error messages */ */ if (column_stat == 2) - ADD_CHAR('\n'); + ADD_CHAR(st, '\n'); column_stat = 0; if (!format_str[fpos]) break; - ADD_CHAR('\n'); + ADD_CHAR(st, '\n'); st->line_start = st->bpos; continue; } @@ -1673,7 +1674,7 @@ static char buff[BUFF_SIZE]; /* For error messages */ column_stat = 0; /* If there was a newline pending, it * will be implicitely added now. */ - ADD_CHAR('\n'); + ADD_CHAR(st, '\n'); st->line_start = st->bpos; /* Handle pending columns and tables */ @@ -1692,7 +1693,7 @@ static char buff[BUFF_SIZE]; /* For error messages */ while (*((*temp)->d.col) == ' ') (*temp)->d.col++; i = (*temp)->start - (st->bpos - st->line_start); - ADD_CHARN(' ', i); + ADD_CHARN(st, ' ', i); column_stat = add_column(st, temp); if (!column_stat) temp = &((*temp)->next); @@ -1701,19 +1702,19 @@ static char buff[BUFF_SIZE]; /* For error messages */ { i = (*temp)->start - (st->bpos - st->line_start); if (i > 0) - ADD_CHARN(' ', i); + ADD_CHARN(st, ' ', i); if (!add_table(st, temp)) temp = &((*temp)->next); } } /* while (*temp) */ if (st->csts || format_str[fpos] == '\n') - ADD_CHAR('\n'); + ADD_CHAR(st, '\n'); st->line_start = st->bpos; } /* while (csts) */ if (column_stat == 2 && format_str[fpos] != '\n') - ADD_CHAR('\n'); + ADD_CHAR(st, '\n'); if (!format_str[fpos]) break; @@ -1726,16 +1727,16 @@ static char buff[BUFF_SIZE]; /* For error messages */ if (format_str[fpos+1] == '%') { - ADD_CHAR('%'); + ADD_CHAR(st, '%'); fpos++; continue; } if (format_str[fpos+1] == '^') { - ADD_CHAR('%'); + ADD_CHAR(st, '%'); fpos++; - ADD_CHAR('^'); + ADD_CHAR(st, '^'); continue; } @@ -1797,16 +1798,16 @@ static char buff[BUFF_SIZE]; /* For error messages */ { if (carg->type != T_NUMBER) ERROR(ERR_INVALID_STAR); - if ((int)(fs = carg->u.number) < 0) + if ((p_int)(fs = carg->u.number) < 0) { #ifdef NO64BIT - if (fs == (unsigned int)PINT_MIN) - fs = PINT_MAX; + if (fs == (unsigned int)PINT_MIN) + fs = PINT_MAX; #else - if (fs == (unsigned int)INT_MIN) - fs = INT_MAX; + if (fs == (unsigned int)INT_MIN) + fs = INT_MAX; #endif - else + else fs = -fs; finfo |= INFO_A_LEFT; } @@ -1940,7 +1941,7 @@ static char buff[BUFF_SIZE]; /* For error messages */ /* never reached... */ fprintf(stderr, "%s: (s)printf: INFO_T_NULL.... found.\n" , get_txt(current_object->name)); - ADD_CHAR('%'); + ADD_CHAR(st, '%'); break; } @@ -2197,7 +2198,7 @@ add_table_now: } else { - ADD_STRN(get_txt(carg->u.str), slen) + ADD_STRN(st, get_txt(carg->u.str), slen); } } break; @@ -2243,12 +2244,13 @@ add_table_now: if ((unsigned int)tmpl < fs) add_aligned(st, temp, tmpl, pad, fs, finfo); else - ADD_STRN(temp, tmpl) + ADD_STRN(st, temp, tmpl); break; } else { - char cheat[6]; /* Synthesized format for sprintf() */ + /* Synthesized format for sprintf() */ + char cheat[6+sizeof(PRI_PINT_PREFIX)-1]; char temp[1024]; /* The buffer must be big enough to hold the biggest float * in non-exponential representation. 1 KByte is hopefully @@ -2258,15 +2260,14 @@ add_table_now: double value; /* The value to print */ int numdig; /* (Estimated) number of digits before the '.' */ Bool zeroCharHack = MY_FALSE; - + char *p = cheat; /* pointer to the format buffer */ int tmpl; - p_uint i = 1; - *cheat = '%'; + *(p++) = '%'; switch (finfo & INFO_PP) { - case INFO_PP_SPACE: cheat[i++] = ' '; break; - case INFO_PP_PLUS: cheat[i++] = '+'; break; + case INFO_PP_SPACE: *(p++) = ' '; break; + case INFO_PP_PLUS: *(p++) = '+'; break; } if ((finfo & INFO_T) == INFO_T_FLOAT) { @@ -2274,10 +2275,10 @@ add_table_now: { ERROR1(ERR_INCORRECT_ARG, format_char); } - cheat[i++] = '.'; - cheat[i++] = '*'; - cheat[i++] = format_char; - cheat[i] = '\0'; + *(p++) = '.'; + *(p++) = '*'; + *(p++) = format_char; + *p = '\0'; value = READ_DOUBLE(carg); @@ -2306,18 +2307,27 @@ add_table_now: ERROR1(ERR_INCORRECT_ARG, format_char); } - /* System sprintf() can handle ("%c", 0), but LDMud + /* System sprintf() can't handle ("%c", 0), but LDMud * strings can. So in that case we format with * character 0x01 and convert to 0 afterwards. */ - if (format_char == 'c' && carg->u.number == 0) - { + if (format_char == 'c') { + if (carg->u.number == 0) + { carg->u.number = 1; zeroCharHack = MY_TRUE; + } } - - cheat[i++] = format_char; - cheat[i] = '\0'; + /* insert the correct length modifier for a p_int + * type. (If the prefix is an empty string, this will + * be probably optimized by the compiler anyway. */ + else { + p = memcpy(p, PRI_PINT_PREFIX, + strlen(PRI_PINT_PREFIX)); + p += strlen(PRI_PINT_PREFIX); + } + *(p++) = format_char; + *p = '\0'; sprintf(temp, cheat, carg->u.number); tmpl = strlen(temp); if ((size_t)tmpl >= sizeof(temp)) @@ -2349,14 +2359,14 @@ add_table_now: * with leading zeroes: preserve the sign * character in the right place. */ - ADD_STRN(temp, 1); + ADD_STRN(st, temp, 1); add_aligned(st, temp+1, tmpl-1, pad, fs-1, finfo); } else add_aligned(st, temp, tmpl, pad, fs, finfo); } else - ADD_STRN(temp, tmpl) + ADD_STRN(st, temp, tmpl); break; } default: /* type not found */ @@ -2376,10 +2386,10 @@ add_table_now: } /* if format entry */ /* Nothing to format: just copy the character */ - ADD_CHAR(format_str[fpos]); + ADD_CHAR(st, format_str[fpos]); } /* for (fpos=0; 1; fpos++) */ - ADD_CHAR('\0'); /* Terminate the formatted string */ + ADD_CHAR(st, '\0'); /* Terminate the formatted string */ /* Restore characters */ while (st->saves) diff --git a/src/strfuns.c b/src/strfuns.c index 78bd7c3..f77ad76 100644 --- a/src/strfuns.c +++ b/src/strfuns.c @@ -328,9 +328,9 @@ trim_all_spaces (const string_t * txt) dest = alloca(mstrsize(txt)); if (dest == NULL) - errorf("Stack overflow (%ld bytes)\n", (long)mstrsize(txt)); + errorf("Stack overflow (%zu bytes)\n", mstrsize(txt)); - src = get_txt(txt); + src = get_txt((string_t *const)txt); srclen = mstrsize(txt); src_ix = 0; dest_ix = 0; @@ -484,20 +484,23 @@ f_convert_charset (svalue_t *sp) if (errno == EILSEQ) { - errorf("convert_charset(): Invalid character sequence at index %ld\n", (long)(pIn - get_txt(in_str))); + errorf("convert_charset(): Invalid character sequence at " + "index %td\n", + (ptrdiff_t)(pIn - get_txt(in_str))); /* NOTREACHED */ return sp; } if (errno == EINVAL) { - errorf("convert_charset(): Incomplete character sequence at index %ld\n", (long)(pIn - get_txt(in_str))); + errorf("convert_charset(): Incomplete character sequence at " + "index %td\n", (ptrdiff_t)(pIn - get_txt(in_str))); /* NOTREACHED */ return sp; } - errorf("convert_charset(): Error %d at index %ld\n" - , errno, (long)(pIn - get_txt(in_str)) + errorf("convert_charset(): Error %d at index %td\n" + , errno, (ptrdiff_t)(pIn - get_txt(in_str)) ); /* NOTREACHED */ return sp; @@ -544,20 +547,22 @@ f_convert_charset (svalue_t *sp) if (errno == EILSEQ) { - errorf("convert_charset(): Invalid character sequence at index %ld\n", (long)(pIn - get_txt(in_str))); + errorf("convert_charset(): Invalid character sequence at " + "index %td\n", (ptrdiff_t)(pIn - get_txt(in_str))); /* NOTREACHED */ return sp; } if (errno == EINVAL) { - errorf("convert_charset(): Incomplete character sequence at index %ld\n", (long)(pIn - get_txt(in_str))); + errorf("convert_charset(): Incomplete character sequence at " + "index %td\n", (ptrdiff_t)(pIn - get_txt(in_str))); /* NOTREACHED */ return sp; } - errorf("convert_charset(): Error %d at index %ld\n" - , errno, (long)(pIn - get_txt(in_str)) + errorf("convert_charset(): Error %d at index %td\n" + , errno, (ptrdiff_t)(pIn - get_txt(in_str)) ); /* NOTREACHED */ return sp; @@ -611,7 +616,7 @@ sort_string (const string_t * p_in, size_t len, long ** pos) size_t step; size_t i, j; - in = get_txt(p_in); + in = get_txt((string_t *const)p_in); out = xalloc(len+1); tmp = xalloc(len+1); if (!out || !tmp) @@ -620,8 +625,8 @@ sort_string (const string_t * p_in, size_t len, long ** pos) xfree(out); if (tmp) xfree(tmp); - errorf("(sort_string) Out of memory (2 * %lu bytes) for temporaries.\n" - , (unsigned long) len+1); + errorf("(sort_string) Out of memory (2 * %zu bytes) for temporaries.\n" + , len+1); } out[len] = '\0'; tmp[len] = '\0'; @@ -641,8 +646,8 @@ sort_string (const string_t * p_in, size_t len, long ** pos) xfree(outpos); if (tmppos) xfree(tmppos); - errorf("(sort_string) Out of memory (2 * %lu bytes) for positions.\n" - , (unsigned long) len*sizeof(*outpos)+1); + errorf("(sort_string) Out of memory (2 * %zu bytes) for positions.\n" + , len*sizeof(*outpos)+1); } } else @@ -828,7 +833,7 @@ intersect_strings (const string_t * p_left, const string_t * p_right, Bool bSubt /* Create the result: copy all flagged characters */ memsafe(result = alloc_mstring(len_out), len_out, "intersection result"); - left_txt = get_txt(p_left); + left_txt = get_txt((string_t *const)p_left); result_txt = get_txt(result); for (ix_left = 0, ix_right = 0; ix_left < len_left; ix_left++) if (matches[ix_left]) @@ -891,14 +896,6 @@ x_filter_string (svalue_t *sp, int num_arg) str = arg->u.str; slen = (mp_int)mstrsize(str); - flags = alloca((size_t)slen+1); - if (!flags) - { - errorf("Stack overflow in filter()"); - /* NOTREACHED */ - return sp; - } - /* Every element in flags is associated by index number with an * element in the vector to filter. The filter function is evaluated * for every string character, and the associated flag is set to 0 @@ -915,11 +912,21 @@ x_filter_string (svalue_t *sp, int num_arg) mapping_t *m; if (num_arg > 2) { - inter_sp = sp; errorf("Too many arguments to filter(array)\n"); } - m = arg[1].u.map; + /* Allocate memory for the flag array. Simultaneously an error + * handler is pushed onto the stack (after the arguments) for freeing + * the buffer in case of runtime errors. */ + flags = xalloc_with_error_handler((size_t)slen + 1); + if (!flags) + { + errorf("Out of memory (%zu bytes) for temporary buffer in filter().\n", + (size_t)slen + 1); + } + sp = inter_sp; + m = arg[1].u.map; + for (src = get_txt(str), cnt = slen; --cnt >= 0; src++) { svalue_t key; @@ -934,9 +941,6 @@ x_filter_string (svalue_t *sp, int num_arg) res++; } - free_svalue(arg+1); /* the mapping */ - sp = arg; - } else { /* --- Filter by function call --- */ @@ -946,19 +950,33 @@ x_filter_string (svalue_t *sp, int num_arg) mp_int cnt; assign_eval_cost(); - inter_sp = sp; + /* setup_efun_callback() will adopt and therefore remove the + * arguments from arg+1 on to arg+num_arg from the stack and update + * inter_sp. New top-of-stack will be arg. */ error_index = setup_efun_callback(&cb, arg+1, num_arg-1); - if (error_index >= 0) { vefun_bad_arg(error_index+2, arg); /* NOTREACHED */ return arg; } - inter_sp = sp = arg+1; + /* push the callback structure onto the stack. */ + sp = arg + 1; put_callback(sp, &cb); + /* Allocate memory for the flag array. Simultaneously an error + * handler is pushed onto the stack (after the arguments) for freeing + * the buffer in case of runtime errors. */ + inter_sp = sp; + flags = xalloc_with_error_handler((size_t)slen + 1); + if (!flags) + { + errorf("Out of memory (%"PRIdMPINT" bytes) for temporary buffer " + "in filter().\n", slen + 1); + } + sp = inter_sp; + /* Loop over all elements in p and call the filter. * w is the current element filtered. */ @@ -989,32 +1007,38 @@ x_filter_string (svalue_t *sp, int num_arg) flags[cnt] = 1; res++; } - - free_callback(&cb); } /* flags[] holds the filter results, res is the number of * elements to keep. Now create the result vector. */ rc = alloc_mstring(res); - if (rc) + if (!rc) { - for (src = get_txt(str), dest = get_txt(rc), flags = &flags[slen] - ; res > 0 ; src++) + errorf("Out of memory (%"PRIdMPINT" bytes) for result in filter().\n", + slen+1); + } + + for (src = get_txt(str), dest = get_txt(rc), flags = &flags[slen] + ; res > 0 ; src++) + { + if (*--flags) { - if (*--flags) - { - *dest++ = *src; - res--; - } + *dest++ = *src; + res--; } } + + /* Cleanup. Arguments for the closure have already been removed. On the + * stack are now the string, the mapping or callback structure and the + * error handler. (Not using pop_n_elems() for 2 elements for saving loop + * and function call overhead.) */ + free_svalue(sp--); /* errorhandler, buffer and flags are freed by this. */ + free_svalue(sp--); /* mapping or callback structure. */ + free_mstring(str); /* string, at arg == sp */ + sp->u.str = rc; /* put result here */ - /* Cleanup (everything but the string has been removed already) */ - free_mstring(str); - arg->u.str = rc; - - return arg; + return sp; } /* x_filter_string() */ /*-------------------------------------------------------------------------*/ @@ -1054,7 +1078,7 @@ x_map_string (svalue_t *sp, int num_arg) arg = sp - num_arg + 1; str = arg->u.str; - len = (mp_int)mstrsize(str); + len = mstrsize(str); if (arg[1].type == T_MAPPING) { @@ -1070,7 +1094,9 @@ x_map_string (svalue_t *sp, int num_arg) res = alloc_mstring(len); if (!res) - errorf("(map_string) Out of memory: string[%ld] for result\n", len); + errorf("(map_string) Out of memory: string[%"PRIdMPINT + "] for result\n", len); + push_string(inter_sp, res); /* In case of errors */ for (src = get_txt(str), dest = get_txt(res); --len >= 0; src++, dest++) @@ -1116,7 +1142,9 @@ x_map_string (svalue_t *sp, int num_arg) res = alloc_mstring(len); if (!res) - errorf("(map_string) Out of memory: string[%ld] for result\n", len); + errorf("(map_string) Out of memory: string[%"PRIdMPINT + "] for result\n", len); + push_string(inter_sp, res); /* In case of errors */ for (src = get_txt(str), dest = get_txt(res); --len >= 0; src++, dest++) diff --git a/src/strfuns.h b/src/strfuns.h index 4659838..dfc878d 100644 --- a/src/strfuns.h +++ b/src/strfuns.h @@ -25,7 +25,8 @@ extern void strbuf_free(strbuf_t * buf); extern void strbuf_add(strbuf_t *buf, const char * text); extern void strbuf_addn(strbuf_t *buf, const char * text, size_t len); extern void strbuf_addc(strbuf_t *buf, const char ch); -extern void strbuf_addf(strbuf_t *buf, const char *format, ...); +extern void strbuf_addf(strbuf_t *buf, const char *format, ...) + FORMATDEBUG(printf,2,3); extern void strbuf_send(strbuf_t *buf); extern void strbuf_store(strbuf_t *buf, svalue_t *svp); extern void strbuf_copy (strbuf_t *buf, char *cbuf); diff --git a/src/string_spec b/src/string_spec index ebf6327..443d81c 100644 --- a/src/string_spec +++ b/src/string_spec @@ -15,7 +15,7 @@ ANONYMOUS "anonymous" ATAT "@@" CALL_OTHER "call_other" CATCH "CATCH" -CL_OBJ_DESTR "Object the closure was bound to has been destructed" +DANGLING_LAMBDA "Dangling function call in lambda closure" CRPATTERN "\015$" DANGLING_V_CL "dangling var closure" DEFAULT_PROMPT "> " @@ -233,6 +233,7 @@ SUCCESS "success" #ifdef USE_SQLITE SQLITE_OPEN "sl_open" +SQLITE_PRAGMA "sqlite_pragma" #endif #ifdef USE_EXPAT diff --git a/src/structs.c b/src/structs.c index 5cdf6df..8cee6bc 100644 --- a/src/structs.c +++ b/src/structs.c @@ -309,10 +309,10 @@ add_type (struct_type_t * pSType) #ifdef DEBUG if (find_by_type(pSType)) - fatal("struct type %s (%s %ld) already in table.\n" + fatal("struct type %s (%s %"PRId32") already in table.\n" , get_txt(struct_t_name(pSType)) , get_txt(struct_t_pname(pSType)) - , (long)struct_t_pid(pSType) + , struct_t_pid(pSType) ); #endif @@ -773,8 +773,8 @@ struct_new_anonymous (int num_members) pType->member[i].name = new_tabled(buf); if (!pType->member[i].name) { - debug_message("(%s:%d) Out of memory (%lu bytes) for member name\n" - , __FILE__, __LINE__, (unsigned long)strlen(buf) + debug_message("(%s:%d) Out of memory (%zu bytes) for member name\n" + , __FILE__, __LINE__, strlen(buf) ); gotError = MY_TRUE; break; @@ -839,7 +839,7 @@ struct_free (struct_t *pStruct) fatal("No wizlist pointer for struct in struct_free()."); if (pStruct->ref != 0) - fatal("Struct with %ld refs passed to struct_free().\n" + fatal("Struct with %"PRIdPINT" refs passed to struct_free().\n" , pStruct->ref); #endif @@ -868,7 +868,7 @@ struct_free_type (struct_type_t *pSType) fatal("NULL pointer passed to struct_free_type().\n"); if (pSType->ref != 0) - fatal("struct typeobject with %ld refs passed to struct_free_type().\n" + fatal("struct typeobject with %"PRIdPINT" refs passed to struct_free_type().\n" , pSType->ref); #endif @@ -982,7 +982,8 @@ total_struct_size (strbuf_t *sbuf, Bool verbose) { if (!verbose) { - strbuf_addf(sbuf, "Structs:\t\t\t%8ld %9ld (%ld types: %ld)\n" + strbuf_addf(sbuf, "Structs:\t\t\t%8"PRIdMPINT" %9"PRIdMPINT + " (%"PRIdMPINT" types: %"PRIdMPINT")\n" , num_struct, size_struct , num_struct_type, size_struct_type ); @@ -1034,10 +1035,10 @@ struct_t_unique_name (struct_type_t *pSType) if (pSType->unique_name) return pSType->unique_name; - sprintf(name, "%s %s #%ld" + snprintf(name, sizeof(name), "%s %s #%"PRId32 , get_txt(struct_t_name(pSType)) , get_txt(struct_t_pname(pSType)) - , (long)struct_t_pid(pSType) + , struct_t_pid(pSType) ); pSType->unique_name = new_mstring(name); @@ -1331,7 +1332,7 @@ x_map_struct (svalue_t *sp, int num_arg) res = struct_new(st->type); if (!res) - errorf("(map_struct) Out of memory: struct[%ld] for result\n", cnt); + errorf("(map_struct) Out of memory: struct[%"PRIdMPINT"] for result\n", cnt); push_struct(inter_sp, res); /* In case of errors */ for (w = st->member, x = res->member; --cnt >= 0; w++, x++) @@ -1369,7 +1370,7 @@ x_map_struct (svalue_t *sp, int num_arg) res = struct_new(st->type); if (!res) - errorf("(map_struct) Out of memory: struct[%ld] for result\n", cnt); + errorf("(map_struct) Out of memory: struct[%"PRIdMPINT"] for result\n", cnt); push_struct(inter_sp, res); /* In case of errors */ /* Loop through arr and res, mapping the values from arr */ @@ -1547,7 +1548,7 @@ f_struct_info (svalue_t *sp) } default: free_svalue(&result); - errorf("Bad arg 2 to struct_info(): illegal value %ld\n" + errorf("Bad arg 2 to struct_info(): illegal value %"PRIdPINT"\n" , sp->u.number); /* NOTREACHED */ return sp; diff --git a/src/swap.c b/src/swap.c index ad9b15b..a3b0810 100644 --- a/src/swap.c +++ b/src/swap.c @@ -612,8 +612,8 @@ store_swap_block (void * buffer, mp_int size) /* Seek and write the data */ if (fseek(swap_file, offset, 0) == -1) { - debug_message("%s Couldn't seek the swap file, errno %d, offset %ld.\n" - , time_stamp(), errno, offset); + debug_message("%s Couldn't seek the swap file, errno %d, " + "offset %"PRIdMPINT".\n", time_stamp(), errno, offset); return -1; } @@ -664,8 +664,8 @@ store_swap_block2 ( void * buffer1, mp_int size1 /* Seek and write the data */ if (fseek(swap_file, offset, 0) == -1) { - debug_message("%s Couldn't seek the swap file, errno %d, offset %ld.\n" - , time_stamp(), errno, offset); + debug_message("%s Couldn't seek the swap file, errno %d, " + "offset %"PRIdMPINT".\n", time_stamp(), errno, offset); return -1; } @@ -700,8 +700,9 @@ swap_program (object_t *ob) if (d_flag > 1) { - debug_message("%s Swap object %s (obj ref %ld, prog ref %ld)\n" - , time_stamp(), get_txt(ob->name), ob->ref, ob->prog->ref); + debug_message("%s Swap object %s (obj ref %"PRIdPINT + ", prog ref %"PRIdPINT")\n", + time_stamp(), get_txt(ob->name), ob->ref, ob->prog->ref); } prog = ob->prog; @@ -1135,10 +1136,10 @@ check_swapped_values (mp_int num, unsigned char * p) if (start + swapsize != p) \ { \ fprintf(stderr \ - , "--- Incorrect swapsize on check: expected %lu bytes, " \ - "read %lu (%p .. %p)\n" \ - , (unsigned long)swapsize \ - , (unsigned long)(p - start), start, p \ + , "--- Incorrect swapsize on check: expected %zu bytes, " \ + "read %zu (%p .. %p)\n" \ + , swapsize \ + , (size_t)(p - start), start, p \ ); \ return NULL; \ } @@ -1284,11 +1285,11 @@ dump_swapped_values (mp_int num, unsigned char * p, int indent) if (start + swapsize != p) \ { \ fprintf(stderr \ - , "%.*s--- Incorrect swapsize: expected %lu bytes, " \ - "read %lu (%p .. %p)\n" \ + , "%.*s--- Incorrect swapsize: expected %zu bytes, " \ + "read %zu (%p .. %p)\n" \ , indent, " " \ - , (unsigned long)swapsize \ - , (unsigned long)(p - start), start, p \ + , swapsize \ + , (size_t)(p - start), start, p \ ); \ } @@ -1299,9 +1300,9 @@ dump_swapped_values (mp_int num, unsigned char * p, int indent) sv.type = *p & ~T_MOD_SWAPPED; /* get the original type */ - fprintf(stderr, "%.*s%08lx (%6ld) [%3ld]: type %d" + fprintf(stderr, "%.*s%16p (%6zu) [%3"PRIdMPINT"]: type %d" , indent, " " - , (unsigned long)p, (unsigned long)(p - block) + , p, (size_t)(p - block) , max_num - num - 1 , sv.type ); @@ -1338,7 +1339,7 @@ dump_swapped_values (mp_int num, unsigned char * p, int indent) p += sizeof size; memcpy(&user, p, sizeof user); p += sizeof user; - fprintf(stderr, " array: %ld values\n", (long)size); + fprintf(stderr, " array: %zu values\n", size); p = dump_swapped_values(size, p, indent+2); if (!p) return NULL; @@ -1380,8 +1381,8 @@ dump_swapped_values (mp_int num, unsigned char * p, int indent) p += sizeof num_keys; memcpy(&user, p, sizeof user); p += sizeof user; - fprintf(stderr, " mapping: %ld keys, %ld values\n" - , (long)num_keys, (long)num_values); + fprintf(stderr, " mapping: %"PRIdPINT" keys, %"PRIdPINT" values\n" + , num_keys, num_values); p = dump_swapped_values(num_keys*(1+num_values), p, indent+2); if (!p) return NULL; @@ -1473,9 +1474,9 @@ free_swapped_svalues (svalue_t *svp, mp_int num, unsigned char *p) if (start + swapsize != p) \ { \ dump_swapped_values(max_num, block, 0); \ - fatal("svalue type %d: expected %lu bytes, read %lu (%p .. %p)\n" \ - , (int)svp->type, (unsigned long)swapsize \ - , (unsigned long)(p - start), start, p \ + fatal("svalue type %d: expected %zu bytes, read %zu (%p .. %p)\n" \ + , (int)svp->type, swapsize \ + , (size_t)(p - start), start, p \ ); \ } @@ -1654,8 +1655,9 @@ swap_variables (object_t *ob) if (fseek(swap_file, last_variable_swap_num + sizeof(p_int), 0) == -1) { - fatal("Couldn't seek the swap file, errno %d, offset %ld.\n", - errno, last_variable_swap_num + sizeof(p_int)); + fatal("Couldn't seek the swap file, errno %d, offset %" + PRIdMPINT".\n", + errno, last_variable_swap_num + sizeof(p_int)); } if (fwrite( last_variable_block, @@ -1673,12 +1675,14 @@ swap_variables (object_t *ob) #ifdef CHECK_OBJECT_STAT if (check_object_stat) { - fprintf(stderr, "DEBUG: OSTAT: (%ld:%ld) swapout( %p '%s') gc %d vars : %ld -> (%ld:%ld)\n" - , tot_alloc_object, tot_alloc_object_size, ob, ob->name ? get_txt(ob->name) : "" - , num_variables - , (long)(num_variables * sizeof (svalue_t)) - , tot_alloc_object, tot_alloc_object_size - (num_variables * sizeof (svalue_t)) - ); + fprintf(stderr, "DEBUG: OSTAT: (%ld:%ld) swapout( %p '%s') gc %d " + "vars : %ld -> (%ld:%ld)\n", + tot_alloc_object, tot_alloc_object_size, ob, + ob->name ? get_txt(ob->name) : "", + num_variables, (long)(num_variables * sizeof (svalue_t)), + tot_alloc_object, + tot_alloc_object_size - (num_variables * sizeof (svalue_t)) + ); } #endif tot_alloc_object_size -= num_variables * sizeof (svalue_t); @@ -1697,8 +1701,8 @@ swap_variables (object_t *ob) if (swapfile_size <= swap_num) fatal("Attempt to swap in from beyond the end of the swapfile.\n"); if (fseek(swap_file, swap_num, 0) == -1) - fatal("Couldn't seek the swap file, errno %d, offset %ld.\n", - errno, swap_num); + fatal("Couldn't seek the swap file, errno %d, offset %" + PRIdPINT".\n", errno, swap_num); if (fread(&num_variables, sizeof num_variables, 1, swap_file) != 1) { @@ -1755,12 +1759,14 @@ swap_variables (object_t *ob) #ifdef CHECK_OBJECT_STAT if (check_object_stat) { - fprintf(stderr, "DEBUG: OSTAT: (%ld:%ld) swapout( %p '%s') %d vars : %ld -> (%ld:%ld)\n" - , tot_alloc_object, tot_alloc_object_size, ob, ob->name ? get_txt(ob->name) : "" - , num_variables - , (long)(num_variables * sizeof (svalue_t)) - , tot_alloc_object, tot_alloc_object_size - (num_variables * sizeof (svalue_t)) - ); + fprintf(stderr, "DEBUG: OSTAT: (%ld:%ld) swapout( %p '%s') %d " + "vars : %ld -> (%ld:%ld)\n", + tot_alloc_object, tot_alloc_object_size, ob, + ob->name ? get_txt(ob->name) : "", + num_variables, (long)(num_variables * sizeof (svalue_t)), + tot_alloc_object, + tot_alloc_object_size - (num_variables * sizeof (svalue_t)) + ); } #endif tot_alloc_object_size -= num_variables * sizeof (svalue_t); @@ -1847,9 +1853,9 @@ read_unswapped_svalues (svalue_t *svp, mp_int num, unsigned char *p) if (start + swapsize != p) \ { \ dump_swapped_values(max_num, block, 0); \ - fatal("svalue type %d: expected %lu bytes, read %lu (%p .. %p)\n" \ - , (int)svp->type, (unsigned long)swapsize \ - , (unsigned long)(p - start), start, p \ + fatal("svalue type %d: expected %zu bytes, read %zu (%p .. %p)\n" \ + , (int)svp->type, swapsize \ + , (size_t)(p - start), start, p \ ); \ } @@ -2161,12 +2167,12 @@ load_ob_from_swap (object_t *ob) if (swapfile_size <= swap_num) fatal("Attempt to swap in from beyond the end of the swapfile.\n"); if (fseek(swap_file, swap_num, 0) == -1) - fatal("Couldn't seek the swap file, errno %d, offset %ld.\n", - errno, swap_num); + fatal("Couldn't seek the swap file, errno %d, offset %" + PRIdPINT".\n", errno, swap_num); if (d_flag > 1) { - debug_message("%s Unswap object %s (ref %ld)\n", time_stamp() - , get_txt(ob->name), ob->ref); + debug_message("%s Unswap object %s (ref %"PRIdPINT")\n", + time_stamp(), get_txt(ob->name), ob->ref); } /* The size of the program is unkown, so read first part to @@ -2226,8 +2232,8 @@ load_ob_from_swap (object_t *ob) if (swapfile_size <= swap_num) fatal("Attempt to swap in from beyond the end of the swapfile.\n"); if (fseek(swap_file, swap_num, 0) == -1) - fatal("Couldn't seek the swap file, errno %d, offset %ld.\n", - errno, swap_num); + fatal("Couldn't seek the swap file, errno %d, offset %" + PRIdPINT".\n", errno, swap_num); if (d_flag > 1) { debug_message("%s Unswap variables of %s\n", time_stamp() @@ -2272,12 +2278,15 @@ load_ob_from_swap (object_t *ob) #ifdef CHECK_OBJECT_STAT if (check_object_stat) { - fprintf(stderr, "DEBUG: OSTAT: (%ld:%ld) swapin( %p '%s') %d vars : %ld -> (%ld:%ld)\n" - , tot_alloc_object, tot_alloc_object_size, ob, ob->name ? get_txt(ob->name) : "" - , ob->prog->num_variables - , (long)(ob->prog->num_variables * sizeof (svalue_t)) - , tot_alloc_object, tot_alloc_object_size + (ob->prog->num_variables * sizeof (svalue_t)) - ); + fprintf(stderr, "DEBUG: OSTAT: (%ld:%ld) swapin( %p '%s') %d " + "vars : %ld -> (%ld:%ld)\n", + tot_alloc_object, tot_alloc_object_size, ob, + ob->name ? get_txt(ob->name) : "", + ob->prog->num_variables, + (long)(ob->prog->num_variables * sizeof (svalue_t)), + tot_alloc_object, tot_alloc_object_size + + (ob->prog->num_variables * sizeof (svalue_t)) + ); } #endif tot_alloc_object_size += ob->prog->num_variables * sizeof (svalue_t); @@ -2306,10 +2315,11 @@ load_ob_from_swap (object_t *ob) #ifdef CHECK_OBJECT_STAT if (check_object_stat) { - fprintf(stderr, "DEBUG: OSTAT: (%ld:%ld) swapin( %p '%s') %d vars failed\n" - , tot_alloc_object, tot_alloc_object_size, ob, ob->name ? get_txt(ob->name) : "" - , ob->prog->num_variables - ); + fprintf(stderr, "DEBUG: OSTAT: (%ld:%ld) swapin( %p '%s') %d " + "vars failed\n", + tot_alloc_object, tot_alloc_object_size, ob, + ob->name ? get_txt(ob->name) : "", + ob->prog->num_variables); } #endif @@ -2348,8 +2358,8 @@ load_line_numbers_from_swap (program_t *prog) if (swapfile_size <= swap_num) fatal("Attempt to swap in from beyond the end of the swapfile.\n"); if (fseek(swap_file, swap_num, 0) == -1) - fatal("Couldn't seek the swap file, errno %d, offset %ld.\n", - errno, swap_num); + fatal("Couldn't seek the swap file, errno %d, offset %" + PRIdPINT".\n", errno, swap_num); if (fread((char *)&tmp_numbers, sizeof tmp_numbers, 1, swap_file) != 1) { fatal("Couldn't read the swap file.\n"); } @@ -2410,8 +2420,8 @@ remove_prog_swap (program_t *prog, Bool load_line_numbers) linenumbers_t tmp_lines; if (fseek(swap_file, swap_num + prog->total_size, 0 ) == -1) - fatal("Couldn't seek the swap file, errno %d, offset %ld.\n", - errno, swap_num); + fatal("Couldn't seek the swap file, errno %d, offset %" + PRIdPINT".\n", errno, swap_num); if (fread(&tmp_lines, sizeof tmp_lines, 1, swap_file) != 1) { fatal("Couldn't read the swap file.\n"); @@ -2482,12 +2492,12 @@ swap_status (strbuf_t *sbuf) */ { - /* maximum seen so far: 10664 var blocks swapped, 5246112 bytes */ - strbuf_addf(sbuf, "%6ld prog blocks swapped,%10ld bytes\n" - "%6ld prog blocks unswapped,%8ld bytes\n" - "%6ld var blocks swapped,%11ld bytes\n" - "%6ld free blocks in swap,%10ld bytes\n" - "Swapfile size:%23ld bytes\n" + /* maximum seen so far: 28574 var blocks swapped, 32754860 bytes */ + strbuf_addf(sbuf, "%10"PRIdMPINT" prog blocks swapped, %13"PRIdMPINT" bytes\n" + "%10"PRIdMPINT" prog blocks unswapped,%12"PRIdMPINT" bytes\n" + "%10"PRIdMPINT" var blocks swapped,%15"PRIdMPINT" bytes\n" + "%10"PRIdMPINT" free blocks in swap,%14"PRIdMPINT" bytes\n" + "Swapfile size:%31"PRIdMPINT" bytes\n" , num_swapped - num_unswapped , total_bytes_swapped - total_bytes_unswapped , num_unswapped, total_bytes_unswapped @@ -2495,11 +2505,11 @@ swap_status (strbuf_t *sbuf) , num_swapfree, total_bytes_swapfree , swapfile_size ); - strbuf_addf(sbuf, "Total reused space:%18ld bytes\n\n" + strbuf_addf(sbuf, "Total reused space:%26"PRIdMPINT" bytes\n\n" , total_swap_reused); strbuf_addf(sbuf - , "Swap: searches: %5ld average search length: %3.1f\n" - "Free: searches: %5ld average search length: %3.1f\n" + , "Swap: searches: %10ld average search length: %3.1f\n" + "Free: searches: %10ld average search length: %3.1f\n" , swap_num_searches , (double)swap_total_searchlength / ( swap_num_searches ? swap_num_searches : 1 ) @@ -2507,9 +2517,9 @@ swap_status (strbuf_t *sbuf) , (double)swap_free_searchlength / ( swap_free_searches ? swap_free_searches : 1 ) ); - strbuf_addf(sbuf, "Overhead: %ld blocks using %ld bytes.\n" - , num_swap_structs, num_swap_structs * sizeof(swap_block_t) - ); + strbuf_addf(sbuf, "Overhead: %"PRIdMPINT" blocks using %" + PRIdMPINT" bytes.\n", + num_swap_structs, num_swap_structs * sizeof(swap_block_t) ); strbuf_addf(sbuf, "Mode: %s - Freespace recycling: %s\n" , swap_compact_mode ? "compact" : "non-compact" , (recycle_free_space || !swap_compact_mode) ? "on" : "off" diff --git a/src/util/indent/Makefile b/src/util/indent/Makefile new file mode 100644 index 0000000..1db85f1 --- /dev/null +++ b/src/util/indent/Makefile @@ -0,0 +1,64 @@ +# Makefile.in for indent +# Based on the original Makefile. +# +# Copyright (c) 1987 Regents of the University of California. +# All rights reserved. +# +# Redistribution and use in source and binary forms are permitted +# provided that the above copyright notice and this paragraph are +# duplicated in all such forms and that any documentation, +# advertising materials, and other materials related to such +# distribution and use acknowledge that the software was developed +# by the University of California, Berkeley. The name of the +# University may not be used to endorse or promote products derived +# from this software without specific prior written permission. +# THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR +# IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED +# WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. +# + +# The placeholders filled in by configure +MAKE=make +SHELL=/bin/sh +INSTALL=/usr/bin/install -c +mkinstalldirs=$(SHELL) ../../mkinstalldirs + +CC=gcc -std=gnu99 + +prefix=/opt/psyced +exec_prefix=${prefix} + +SUBDIRS = +SED = sed + +BINDIR=/opt/psyced/bin +MUD_LIB=/opt/psyced/world +ERQ_DIR=/opt/psyced/run + +# --------------------------------------------------------- + +CFLAGS= -g + +SRCS= indent.c io.c lexi.c parse.c pr_comment.c args.c globs.c +OBJS= indent.o io.o lexi.o parse.o pr_comment.o args.o globs.o +HEADERS= indent_globs.h version.h +MAN= indent.texinfo ChangeLog Projects + +all: indent + +indent: ${OBJS} ${LIBC} + ${CC} -o $@ ${LDFLAGS} ${OBJS} + +indent.tar.Z: ${SRCS} Makefile ${MAN} ${HEADERS} + tar -c -z -f indent.tar.Z ${SRCS} Makefile ${MAN} ${HEADERS} + +${OBJS}: indent_globs.h +args.o: version.h + +clean: + rm -f ${OBJS} core indent + +install: indent + cp $? ${BINDIR} +# $(INSTALL) -c -s $? $(BINDIR) + diff --git a/src/util/indent/Makefile.in b/src/util/indent/Makefile.in new file mode 100644 index 0000000..a47633d --- /dev/null +++ b/src/util/indent/Makefile.in @@ -0,0 +1,64 @@ +# Makefile.in for indent +# Based on the original Makefile. +# +# Copyright (c) 1987 Regents of the University of California. +# All rights reserved. +# +# Redistribution and use in source and binary forms are permitted +# provided that the above copyright notice and this paragraph are +# duplicated in all such forms and that any documentation, +# advertising materials, and other materials related to such +# distribution and use acknowledge that the software was developed +# by the University of California, Berkeley. The name of the +# University may not be used to endorse or promote products derived +# from this software without specific prior written permission. +# THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR +# IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED +# WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. +# + +# The placeholders filled in by configure +MAKE=make +SHELL=@CONFIG_SHELL@ +INSTALL=@INSTALL@ +mkinstalldirs=$(SHELL) @top_srcdir@/mkinstalldirs + +CC=@CC@ + +prefix=@prefix@ +exec_prefix=@exec_prefix@ + +SUBDIRS = +SED = sed + +BINDIR=@bindir@ +MUD_LIB=@libdir@ +ERQ_DIR=@libexecdir@ + +# --------------------------------------------------------- + +CFLAGS= -g + +SRCS= indent.c io.c lexi.c parse.c pr_comment.c args.c globs.c +OBJS= indent.o io.o lexi.o parse.o pr_comment.o args.o globs.o +HEADERS= indent_globs.h version.h +MAN= indent.texinfo ChangeLog Projects + +all: indent + +indent: ${OBJS} ${LIBC} + ${CC} -o $@ ${LDFLAGS} ${OBJS} + +indent.tar.Z: ${SRCS} Makefile ${MAN} ${HEADERS} + tar -c -z -f indent.tar.Z ${SRCS} Makefile ${MAN} ${HEADERS} + +${OBJS}: indent_globs.h +args.o: version.h + +clean: + rm -f ${OBJS} core indent + +install: indent + cp $? ${BINDIR} +# $(INSTALL) -c -s $? $(BINDIR) + diff --git a/src/util/indent/Projects b/src/util/indent/Projects new file mode 100644 index 0000000..4685068 --- /dev/null +++ b/src/util/indent/Projects @@ -0,0 +1,24 @@ +Make it so that the line numbers indent reports are the real line +numbers (currently it is often off by a few). + +Error recover should probably be enhanced. At a minimum, "indent +foo.c" should not overwrite foo.c when it gets an error. Fancy error +recover is probably not worth the effort because indent is pretty +fast. Stopping after the first error might be more helpful than the +current error cascades. + +Also, there is a bug in that indent flags the following as illegal: +enum bar { a = 1, b = 2 }; + +Make the -nss option cause + while (foo) + ; +This is the real alternative to + while (foo) ; + +Look at all the undocumented options, and determine which of them are +bug-free enough that they should be documented. + +Look at termcap interface from Berkeley (and other recent enhancements +not in 4.3-tahoe) and see whether it is worth merging those changes +into our indent or our indent into Berkeley's. diff --git a/src/util/indent/args.c b/src/util/indent/args.c new file mode 100644 index 0000000..1cac294 --- /dev/null +++ b/src/util/indent/args.c @@ -0,0 +1,416 @@ +/* + * Copyright (c) 1985 Sun Microsystems, Inc. + * Copyright (c) 1980 The Regents of the University of California. + * Copyright (c) 1976 Board of Trustees of the University of Illinois. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley, the University of Illinois, + * Urbana, and Sun Microsystems, Inc. The name of either University + * or Sun Microsystems may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifndef lint +static char sccsid[] = "@(#)args.c 5.6 (Berkeley) 9/15/88"; +#endif /* not lint */ + +/* + * Argument scanning and profile reading code. Default parameters are set + * here as well. + */ + +#include "indent_globs.h" +#include +#include "version.h" + +int else_endif_col; + +extern char *in_name; + +char *getenv(); + +/* profile types */ +enum profile {PRO_BOOL, /* boolean */ + PRO_INT, /* integer */ + PRO_FONT, /* troff font */ + PRO_IGN, /* ignore it */ + PRO_STDIN, /* -st switch */ + PRO_KEY, /* -T switch */ + PRO_SETTINGS, /* bundled set of settings */ + PRO_PRSTRING /* Print string and exit */ + }; + +/* profile specials for booleans */ +enum on_or_off {OFF,ON}; + +/* Explicit flags for each option. */ +static int exp_T = 0; +static int exp_bacc = 0; +static int exp_badp = 0; +static int exp_bad = 0; +static int exp_bap = 0; +static int exp_bbb = 0; +static int exp_bc = 0; +static int exp_bli = 0; +static int exp_bl = 0; +static int exp_bs = 0; +static int exp_cdb = 0; +static int exp_cd = 0; +static int exp_ce = 0; +static int exp_ci = 0; +static int exp_cli = 0; +static int exp_cp = 0; +static int exp_c = 0; +static int exp_di = 0; +static int exp_dj = 0; +static int exp_d = 0; +static int exp_eei = 0; +static int exp_ei = 0; +static int exp_fbc = 0; +static int exp_fbx = 0; +static int exp_fb = 0; +static int exp_fc1 = 0; +static int exp_fca = 0; +static int exp_fc = 0; +static int exp_fk = 0; +static int exp_fs = 0; +static int exp_gnu = 0; +static int exp_ip = 0; +static int exp_i = 0; +static int exp_lc = 0; +static int exp_lp = 0; +static int exp_l = 0; +static int exp_pcs = 0; +static int exp_psl = 0; +static int exp_pro = 0; +static int exp_ps = 0; +static int exp_kr = 0; +static int exp_sc = 0; +static int exp_sob = 0; +static int exp_ss = 0; +static int exp_st = 0; +static int exp_troff = 0; +static int exp_v = 0; +static int exp_version = 0; +static int exp_lpc = 0; + +/* The following variables are controlled by command line parameters and + their meaning is explained in indent_globs.h. */ +int leave_comma; +int decl_com_ind; +int case_indent; +int com_ind; +int decl_indent; +int ljust_decl; +int unindent_displace; +int else_if; +int indent_parameters; +int ind_size; +int blanklines_after_procs; +int lpc; +int noarrowspace; + +/* + * N.B.: because of the way the table here is scanned, options whose names are + * substrings of other options must occur later; that is, with -lp vs -l, -lp + * must be first. Also, while (most) booleans occur more than once, the last + * default value is the one actually assigned. + */ +struct pro { + char *p_name; /* name, eg -bl, -cli */ + enum profile p_type; + int p_default; /* the default value (if int) */ + + /* If p_type == PRO_BOOL, ON or OFF to tell how this switch affects + the variable. + Not used for other p_type's. */ + enum on_or_off p_special; + + /* if p_type == PRO_SETTINGS, a (char *) pointing to a list of the + switches to set, separated by NULs, terminated by 2 NULs. + if p_type == PRO_BOOL, PRO_INT, or PRO_FONT, address of the + variable that gets set by the option. + if p_type == PRO_PRSTRING, a (char *) pointing to the string. */ + int *p_obj; + + /* Points to a nonzero value (allocated statically for all options) + if the option has been specified explicitly. This is necessary + because for boolean options, the options to set and reset the + variable must share the explicit flag. */ + int* p_explicit; +}; + +struct pro pro[] = { + + {"T", PRO_KEY, 0, 0, 0, &exp_T}, + {"bacc", PRO_BOOL, false, ON, + &blanklines_around_conditional_compilation, &exp_bacc}, + {"badp", PRO_BOOL, false, ON, + &blanklines_after_declarations_at_proctop, &exp_badp}, + {"bad", PRO_BOOL, false, ON, &blanklines_after_declarations, &exp_bad}, + {"bap", PRO_BOOL, false, ON, &blanklines_after_procs, &exp_bap}, + {"bbb", PRO_BOOL, false, ON, &blanklines_before_blockcomments, &exp_bbb}, + {"bc", PRO_BOOL, true, OFF, &leave_comma, &exp_bc}, + {"bli", PRO_INT, 0, 0, &brace_indent, &exp_bli}, + {"bl", PRO_BOOL, true, OFF, &btype_2, &exp_bl}, + {"br", PRO_BOOL, true, ON, &btype_2, &exp_bl}, + {"bs", PRO_BOOL, false, ON, &Bill_Shannon, &exp_bs}, + {"cdb", PRO_BOOL, true, ON, &comment_delimiter_on_blankline, &exp_cdb}, + {"cd", PRO_INT, 0, 0, &decl_com_ind, &exp_cd}, + {"ce", PRO_BOOL, true, ON, &cuddle_else, &exp_ce}, + {"ci", PRO_INT, 0, 0, &continuation_indent, &exp_ci}, + {"cli", PRO_INT, 0, 0, &case_indent, &exp_cli}, + {"cp", PRO_INT, 33, 0, &else_endif_col, &exp_cp}, + {"c", PRO_INT, 33, 0, &com_ind, &exp_c}, + {"di", PRO_INT, 16, 0, &decl_indent, &exp_di}, + {"dj", PRO_BOOL, false, ON, &ljust_decl, &exp_dj}, + {"d", PRO_INT, 0, 0, &unindent_displace, &exp_d}, + {"eei", PRO_BOOL, false, ON, &extra_expression_indent, &exp_eei}, + {"ei", PRO_BOOL, true, ON, &else_if, &exp_ei}, + {"fbc", PRO_FONT, 0, 0, (int *) &blkcomf, &exp_fbc}, + {"fbx", PRO_FONT, 0, 0, (int *) &boxcomf, &exp_fbx}, + {"fb", PRO_FONT, 0, 0, (int *) &bodyf, &exp_fb}, + {"fc1", PRO_BOOL, true, ON, &format_col1_comments, &exp_fc1}, + {"fca", PRO_BOOL, true, ON, &format_comments, &exp_fca}, + {"fc", PRO_FONT, 0, 0, (int *) &scomf, &exp_fc}, + {"fk", PRO_FONT, 0, 0, (int *) &keywordf, &exp_fk}, + {"fs", PRO_FONT, 0, 0, (int *) &stringf, &exp_fs}, + {"gnu", PRO_SETTINGS, 0, 0, + (int *)"-nbad\0-bap\0-nbbb\0-nbc\0-bl\0-ncdb\0-nce\0-di0\0-ndj\0\ +-ei\0-nfc1\0-i2\0-ip5\0-lp\0-pcs\0-nps\0-psl\0-nsc\0-nsob\0-bli2\0-ss\0\ +-cp1\0-nfca\0", &exp_gnu}, + {"ip", PRO_INT, 4, ON, &indent_parameters, &exp_ip}, + {"i", PRO_INT, 4, 0, &ind_size, &exp_i}, + {"kr", PRO_SETTINGS, 0, 0, + (int *)"-nbad\0-bap\0-nbbb\0-nbc\0-br\0-c33\0-cd33\0-ncdb\0-ce\0\ +-ci4\0-cli0\0-d0\0-di1\0-nfc1\0-i4\0-ip0\0-l75\0-lp\0-npcs\0-npsl\0\ +-nsc\0-nsc\0-nsob\0-nfca\0-cp33\0-nss\0", &exp_kr}, + {"lpc", PRO_BOOL, false, ON, &lpc, &exp_lpc}, + {"lc", PRO_INT, 0, 0, &block_comment_max_col, &exp_lc}, + {"lp", PRO_BOOL, true, ON, &lineup_to_parens, &exp_lp}, + {"l", PRO_INT, 78, 0, &max_col, &exp_l}, + {"nbacc", PRO_BOOL, false, ON, + &blanklines_around_conditional_compilation, &exp_bacc}, + {"nbadp", PRO_BOOL, false, OFF, + &blanklines_after_declarations_at_proctop, &exp_badp}, + {"nbad", PRO_BOOL, false, OFF, &blanklines_after_declarations, &exp_bad}, + {"nbap", PRO_BOOL, false, OFF, &blanklines_after_procs, &exp_bap}, + {"nbbb", PRO_BOOL, false, OFF, &blanklines_before_blockcomments, &exp_bbb}, + {"nbc", PRO_BOOL, true, ON, &leave_comma, &exp_bc}, + {"nbs", PRO_BOOL, false, OFF, &Bill_Shannon, &exp_bs}, + {"ncdb", PRO_BOOL, true, OFF, &comment_delimiter_on_blankline, &exp_cdb}, + {"nce", PRO_BOOL, true, OFF, &cuddle_else, &exp_ce}, + {"ndj", PRO_BOOL, false, OFF, &ljust_decl, &exp_dj}, + {"neei", PRO_BOOL, false, OFF, &extra_expression_indent, &exp_eei}, + {"nei", PRO_BOOL, true, OFF, &else_if, &exp_ei}, + {"nfc1", PRO_BOOL, true, OFF, &format_col1_comments, &exp_fc1}, + {"nfca", PRO_BOOL, true, OFF, &format_comments, &exp_fca}, + {"nlp", PRO_BOOL, true, OFF, &lineup_to_parens, &exp_lp}, + {"npcs", PRO_BOOL, false, OFF, &proc_calls_space, &exp_pcs}, + {"npro", PRO_IGN, 0, 0, 0, &exp_pro}, + {"npsl", PRO_BOOL, true, OFF, &procnames_start_line, &exp_psl}, + {"nps", PRO_BOOL, false, OFF, &pointer_as_binop, &exp_ps}, + {"nsc", PRO_BOOL, true, OFF, &star_comment_cont, &exp_sc}, + {"nsob", PRO_BOOL, false, OFF, &swallow_optional_blanklines, &exp_sob}, + {"nss", PRO_BOOL, false, OFF, &space_sp_semicolon, &exp_ss}, + {"nv", PRO_BOOL, false, OFF, &verbose, &exp_v}, + {"pcs", PRO_BOOL, false, ON, &proc_calls_space, &exp_pcs}, + {"psl", PRO_BOOL, true, ON, &procnames_start_line, &exp_psl}, + {"ps", PRO_BOOL, false, ON, &pointer_as_binop, &exp_ps}, + {"sc", PRO_BOOL, true, ON, &star_comment_cont, &exp_sc}, + {"sob", PRO_BOOL, false, ON, &swallow_optional_blanklines, &exp_sob}, + {"ss", PRO_BOOL, false, ON, &space_sp_semicolon, &exp_ss}, + {"st", PRO_STDIN, 0, 0, 0, &exp_st}, + {"troff", PRO_BOOL, false, ON, &troff, &exp_troff}, + {"version", PRO_PRSTRING, 0, 0, (int *)VERSION_STRING, &exp_version}, + {"v", PRO_BOOL, false, ON, &verbose, &exp_v}, + + /* Signify end of structure. */ + {0, 0, 0, 0, 0, 0} +}; + +/* + * set_profile reads $HOME/.indent.pro and ./.indent.pro and handles arguments + * given in these files. + */ +set_profile() +{ + register FILE *f; + char *fname; +#ifndef MSDOS + static char prof[] = ".indent.pro"; +#else + static char prof[] = "indent.pro"; +#endif + char *homedir; + + homedir = getenv("HOME"); + fname = xmalloc(strlen(homedir) + 10 + sizeof prof); + sprintf(fname, "%s/%s", homedir, prof); + if ((f = fopen(prof, "r")) != NULL) { + scan_profile(f); + (void) fclose(f); + } + if ((f = fopen(fname, "r")) != NULL) { + scan_profile(f); + (void) fclose(f); + } + free (fname); +} + +scan_profile(f) + register FILE *f; +{ + register int i; + register char *p; + char buf[BUFSIZ]; + + while (1) { + for (p = buf; (i = getc(f)) != EOF && (*p = i) > ' '; ++p); + if (p != buf) { + *p++ = 0; + if (verbose) + printf("profile: %s\n", buf); + set_option(buf, 1); + } + else if (i == EOF) + return; + } +} + +/* S1 should be a string. S2 should be a string, perhaps followed by + an argument. Compare the two, returning true if they are equal, + and if they are equal set *START_PARAM to point to the argument + in S2. */ +eqin(s1, s2, start_param) + register char *s1; + register char *s2; + char **start_param; +{ + while (*s1) { + if (*s1++ != *s2++) + return (false); + } + *start_param = s2; + return (true); +} + +/* + * Set the defaults. + */ +set_defaults() +{ + register struct pro *p; + + for (p = pro; p->p_name; p++) + if (p->p_type == PRO_BOOL || p->p_type == PRO_INT) + *p->p_obj = p->p_default; +} + +/* Process an option ARG (e.g. "-l60"). + EXPLICIT should be nonzero iff the argument is being explicitly + specified (as opposed to being taken from a PRO_SETTINGS group of + settings). */ + +set_option (arg, explicit) + char *arg; + int explicit; +{ + struct pro *p; + char *param_start; + + arg++; /* ignore leading "-" */ + for (p = pro; p->p_name; p++) + if (*p->p_name == *arg && eqin(p->p_name, arg, ¶m_start)) + goto found; + fprintf(stderr, "indent: unknown parameter \"%s\"\n", arg - 1); + exit(1); +found: + /* If the parameter has been explicitly specified, we don't */ + /* want a group of bundled settings to override the explicit */ + /* setting. */ + if (explicit || !*(p->p_explicit)) + { + if (explicit) + *(p->p_explicit) = 1; + + switch (p->p_type) { + + case PRO_PRSTRING: + puts ((char *)p->p_obj); + exit (0); + + case PRO_SETTINGS: + { + char *t; /* current position */ + + t = (char *)p->p_obj; + do + { + set_option(t, 0); + /* advance to character following next NUL */ + while (*t++) ; + } + while (*t); + } + + case PRO_IGN: + break; + + case PRO_STDIN: + if (in_name == 0) + { + read_stdin(); + /* Let it be known that we have an input file. */ + in_name = "Standard Input"; + } + if (output == 0) + output = stdout; + break; + + case PRO_KEY: + if (*param_start == 0) + goto need_param; + { + register char *str = (char *) xmalloc(strlen(param_start) + 1); + strcpy(str, param_start); + addkey(str, 4); + } + break; + + case PRO_BOOL: + if (p->p_special == OFF) + *p->p_obj = false; + else + *p->p_obj = true; + break; + + case PRO_INT: + if (*param_start == 0) { + need_param: + fprintf(stderr, "indent: ``%s'' requires a parameter\n", + arg - 1); + exit(1); + } + *p->p_obj = atoi(param_start); + break; + + case PRO_FONT: + parsefont((struct fstate *) p->p_obj, param_start); + break; + + default: + fprintf(stderr, "indent: set_option: internal error: p_type %d\n", + p->p_type); + exit(1); + } + } +} diff --git a/src/util/indent/globs.c b/src/util/indent/globs.c new file mode 100644 index 0000000..6e12620 --- /dev/null +++ b/src/util/indent/globs.c @@ -0,0 +1,51 @@ +/* Copyright (C) 1986, 1989 Free Software Foundation, Inc. + +This file is part of GNU indent. + +GNU indent 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 1, or (at your option) +any later version. + +GNU indent 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 GNU indent; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "indent_globs.h" + +/* Like malloc but get error if no storage available. */ + +char * +xmalloc (size) + long size; +{ + register char *val = (char *) calloc (1, size); + if (!val) + { + fprintf (stderr,"indent: Virtual memory exhausted.\n"); + exit (1); + } + return val; +} + +/* Like realloc but get error if no storage available. */ + +char * +xrealloc (ptr, size) + char *ptr; + long size; +{ + register char *val = (char *) realloc (ptr, size); + if (!val) + { + fprintf (stderr,"indent: Virtual memory exhausted.\n"); + exit (1); + } + return val; +} + diff --git a/src/util/indent/hosts/next/Makefile b/src/util/indent/hosts/next/Makefile new file mode 100644 index 0000000..34f9890 --- /dev/null +++ b/src/util/indent/hosts/next/Makefile @@ -0,0 +1,49 @@ +# +# Copyright (c) 1987 Regents of the University of California. +# All rights reserved. +# +# Redistribution and use in source and binary forms are permitted +# provided that the above copyright notice and this paragraph are +# duplicated in all such forms and that any documentation, +# advertising materials, and other materials related to such +# distribution and use acknowledge that the software was developed +# by the University of California, Berkeley. The name of the +# University may not be used to endorse or promote products derived +# from this software without specific prior written permission. +# THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR +# IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED +# WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. +# +# @(#)Makefile 5.9 (Berkeley) 9/15/88 +# +CFLAGS= -g +#LDFLAGS= -g +#LDFLAGS= +#LIBC= /lib/libc.a +#LIBC= /usr/lib/libc.a +SRCS= indent.c io.c lexi.c parse.c pr_comment.c args.c globs.c +OBJS= indent.o io.o lexi.o parse.o pr_comment.o args.o globs.o +HEADERS= indent_globs.h version.h +MAN= indent.texinfo ChangeLog Projects +# -g is here rather than in CFLAGS since many versions of cc do not +# allow -g with -O +CC=gcc + +all: indent + +indent: ${OBJS} ${LIBC} + ${CC} -o $@ ${LDFLAGS} ${OBJS} + cp indent $(BINDIR)/indent + +indent.tar.Z: ${SRCS} Makefile ${MAN} ${HEADERS} + tar -c -z -f indent.tar.Z ${SRCS} Makefile ${MAN} ${HEADERS} + +${OBJS}: indent_globs.h +args.o: version.h + +clean: + rm -f ${OBJS} core indent + +install: indent + install -c -s indent $(BINDIR) + diff --git a/src/util/indent/indent.c b/src/util/indent/indent.c new file mode 100644 index 0000000..784dc82 --- /dev/null +++ b/src/util/indent/indent.c @@ -0,0 +1,1382 @@ +/* + * Copyright (c) 1985 Sun Microsystems, Inc. + * Copyright (c) 1980 The Regents of the University of California. + * Copyright (c) 1976 Board of Trustees of the University of Illinois. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley, the University of Illinois, + * Urbana, and Sun Microsystems, Inc. The name of either University + * or Sun Microsystems may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifndef lint +char copyright[] = +"@(#) Copyright (c) 1985 Sun Microsystems, Inc.\n\ + @(#) Copyright (c) 1980 The Regents of the University of California.\n\ + @(#) Copyright (c) 1976 Board of Trustees of the University of Illinois.\n\ + All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)indent.c 5.11 (Berkeley) 9/15/88"; +#endif /* not lint */ + +#define MAIN +#include "indent_globs.h" +#include + +char *in_name = 0; /* will always point to name of input + * file */ +char *out_name = 0; /* will always point to name + * of output file */ + +/* The following variables are documented in indent_globs.h. */ +int else_or_endif = false; + +main(argc, argv) + int argc; + char **argv; +{ + + extern int found_err; /* flag set in diag() on error */ + int dec_ind; /* current indentation for declarations */ + int di_stack[20]; /* a stack of structure indentation levels */ + int flushed_nl; /* used when buffering up comments to remember + * that a newline was passed over */ + int force_nl; /* when true, code must be broken */ + int hd_type; /* used to store type of stmt for if (...), + * for (...), etc */ + register int i; /* local loop counter */ + int scase; /* set to true when we see a case, so we will + * know what to do with the following colon */ + int sp_sw; /* when true, we are in the expressin of + * if(...), while(...), etc. */ + + /* True if we have just encountered the end of an if (...), etc. + (i.e. the ')' of the if (...) was the last token). The variable + is set to 2 in the middle of the main token reading loop and is + decremented at the beginning of the loop, so it will reach zero + when the second token after the ')' is read. */ + int last_token_ends_sp; + + int squest; /* when this is positive, we have seen a ? + * without the matching : in a ?: + * construct */ + register char *t_ptr; /* used for copying tokens */ + enum codes type_code; /* the type of token, returned by lexi */ + + int last_else = 0; /* true iff last keyword was an else */ + + + /*-----------------------------------------------*\ + | INITIALIZATION | + \*-----------------------------------------------*/ + + parser_state_tos = (struct parser_state *) + xmalloc(sizeof(struct parser_state)); + parser_state_tos->next = 0; + /* Allocate initial stacks for the parser. */ + parser_state_tos->p_stack_size = INITIAL_STACK_SIZE; + parser_state_tos->p_stack = (enum codes *) xmalloc + (parser_state_tos->p_stack_size * sizeof (enum codes)); + parser_state_tos->il = (int *) xmalloc + (parser_state_tos->p_stack_size * sizeof (int)); + parser_state_tos->cstk = (int *) xmalloc + (parser_state_tos->p_stack_size * sizeof (int)); + + parser_state_tos->paren_indents_size = 1; + parser_state_tos->paren_indents = (short *) xmalloc + (parser_state_tos->paren_indents_size * sizeof (short)); + + parser_state_tos->p_stack[0] = stmt; /* this is the parser's stack */ + parser_state_tos->last_nl = true; /* this is true if the last thing scanned was + * a newline */ + parser_state_tos->last_token = semicolon; + combuf = (char *) xmalloc(bufsize); + labbuf = (char *) xmalloc(bufsize); + codebuf = (char *) xmalloc(bufsize); + l_com = combuf + bufsize - 5; + l_lab = labbuf + bufsize - 5; + l_code = codebuf + bufsize - 5; + combuf[0] = codebuf[0] = labbuf[0] = ' '; /* set up code, label, and + * comment buffers */ + combuf[1] = codebuf[1] = labbuf[1] = '\0'; + else_if = 1; /* Default else-if special processing to on */ + s_lab = e_lab = labbuf + 1; + s_code = e_code = codebuf + 1; + s_com = e_com = combuf + 1; + + init_buf(save_com); + + line_no = 1; + had_eof = parser_state_tos->in_decl = parser_state_tos->decl_on_line = break_comma = false; + sp_sw = force_nl = false; + parser_state_tos->in_or_st = false; + parser_state_tos->bl_line = true; + dec_ind = 0; + di_stack[parser_state_tos->dec_nest = 0] = 0; + parser_state_tos->want_blank = parser_state_tos->in_stmt = parser_state_tos->ind_stmt = false; + parser_state_tos->procname = parser_state_tos->procname_end = "\0"; + + scase = parser_state_tos->pcase = false; + squest = 0; + bp_save = 0; + be_save = 0; + + output = 0; + + + + /*--------------------------------------------------*\ + | COMMAND LINE SCAN | + \*--------------------------------------------------*/ + + for (i = 1; i < argc; ++i) + if (strcmp(argv[i], "-npro") == 0) + break; + set_defaults(); + if (i >= argc) + set_profile(); + + for (i = 1; i < argc; ++i) { + + /* + * look thru args (if any) for changes to defaults + */ + + if (argv[i][0] != '-') {/* no flag on parameter */ + if (in_name == 0) { /* we must have the input file */ + in_name = argv[i]; /* remember name of input file */ + read_file(in_name); + continue; + } + else if (out_name == 0) { /* we have the output file */ + out_name = argv[i]; /* remember name of output file */ + continue; + } + fprintf(stderr, "indent: unknown parameter: %s\n", argv[i]); + exit(1); + } + else + set_option(argv[i],1); + } /* end of for */ + if (in_name == 0) { + fprintf(stderr, "indent: usage: indent file [ outfile ] [ options ]\n"); + exit(1); + } + if (out_name) + { + if (strcmp(in_name, out_name) == 0) { /* attempt to overwrite + * the file */ + fprintf(stderr, "indent: input and output files must be different\n"); + exit(1); + } + output = fopen(out_name, "w"); + if (output == 0) { /* check for create error */ + fprintf(stderr, "indent: can't create %s\n", argv[i]); + exit(1); + } + } + if (output == 0) + { + if (troff) + output = stdout; + else { + out_name = in_name; + bakcopy(); + } + } + if (com_ind <= 1) + com_ind = 2; /* dont put normal comments before column 2 */ + if (troff) { + if (bodyf.font[0] == 0) + parsefont(&bodyf, "R"); + if (scomf.font[0] == 0) + parsefont(&scomf, "I"); + if (blkcomf.font[0] == 0) + blkcomf = scomf, blkcomf.size += 2; + if (boxcomf.font[0] == 0) + boxcomf = blkcomf; + if (stringf.font[0] == 0) + parsefont(&stringf, "L"); + if (keywordf.font[0] == 0) + parsefont(&keywordf, "B"); + writefdef(&bodyf, 'B'); + writefdef(&scomf, 'C'); + writefdef(&blkcomf, 'L'); + writefdef(&boxcomf, 'X'); + writefdef(&stringf, 'S'); + writefdef(&keywordf, 'K'); + } + if (lpc) { + addkey("string", 4); + addkey("object", 4); + } else { + addkey("long", 4); + addkey("short", 4); + } + if (block_comment_max_col <= 0) + block_comment_max_col = max_col; + if (decl_com_ind <= 0) /* if not specified by user, set this */ + decl_com_ind = + ljust_decl ? (com_ind <= 10 ? 2 : com_ind - 8) : com_ind; + if (continuation_indent == 0) + continuation_indent = ind_size; + fill_buffer(); /* get first batch of stuff into input buffer */ + + parse(semicolon); + { + register char *p = buf_ptr; + register col = 1; + + while (1) { + if (*p == ' ') + col++; + else if (*p == '\t') + col = ((col - 1) & ~7) + 9; + else + break; + p++; + }; + if (col > ind_size) + parser_state_tos->ind_level = parser_state_tos->i_l_follow = col; + } + if (troff) { + register char *p = in_name, + *beg = in_name; + + while (*p) + if (*p++ == '/') + beg = p; + fprintf(output, ".Fn \"%s\"\n", beg); + } + /* + * START OF MAIN LOOP + */ + + while (1) { /* this is the main loop. it will go until we + * reach eof */ + int is_procname; + + type_code = lexi(); /* lexi reads one token. "token" points to + the actual characters. lexi + returns a code indicating the type of token */ + + if (last_token_ends_sp > 0) + last_token_ends_sp--; + is_procname = parser_state_tos->procname[0]; + + /* + * The following code moves everything following an if (), while (), + * else, etc. up to the start of the following stmt to a buffer. This + * allows proper handling of both kinds of brace placement. + */ + + flushed_nl = false; + while (parser_state_tos->search_brace) + { + /* After scanning an if(), while (), etc., it might be + necessary to keep track of the text between the if() and + the start of the statement which follows. Use save_com + to do so. */ + + switch (type_code) { + case newline: + ++line_no; + flushed_nl = true; + case form_feed: + break; /* form feeds and newlines found here will be + * ignored */ + + case lbrace: /* this is a brace that starts the compound + * stmt */ + if (save_com.end == save_com.ptr) { /* ignore buffering if a comment wasnt + stored up */ + parser_state_tos->search_brace = false; + goto check_type; + } + if (btype_2) { + save_com.ptr[0] = '{'; /* we either want to put the brace + * right after the if */ + goto sw_buffer; /* go to common code to get out of + * this loop */ + } + case comment: /* we have a comment, so we must copy it into + * the buffer */ + if (!flushed_nl || save_com.end != save_com.ptr) + { + need_chars(save_com,10); + if (save_com.end == save_com.ptr) { /* if this is the first comment, we + * must set up the buffer */ + save_com.ptr[0] = save_com.ptr[1] = ' '; + save_com.end = save_com.ptr + 2; + } + else { + *save_com.end++ = '\n'; /* add newline between + * comments */ + *save_com.end++ = ' '; + --line_no; + } + *save_com.end++ = '/'; /* copy in start of comment */ + *save_com.end++ = '*'; + + for (;;) { /* loop until we get to the end of the comment */ + /* make sure there is room for this character and + (while we're at it) the '/' we might add + at the end of the loop. */ + need_chars(save_com,2); + *save_com.end = *buf_ptr++; + if (buf_ptr >= buf_end) + fill_buffer(); + + if (*save_com.end++ == '*' && *buf_ptr == '/') + break; /* we are at end of comment */ + + } + *save_com.end++ = '/'; /* add ending slash */ + if (++buf_ptr >= buf_end) /* get past / in buffer */ + fill_buffer(); + break; + } + default: /* it is the start of a normal statment */ + if (flushed_nl) /* if we flushed a newline, make sure it is + * put back */ + force_nl = true; + if (type_code == sp_paren && *token == 'i' + && last_else && else_if + || type_code == sp_nparen && *token == 'e' + && e_code != s_code && e_code[-1] == '}') + force_nl = false; + + if (save_com.end == save_com.ptr) { /* ignore buffering if comment wasnt + * saved up */ + parser_state_tos->search_brace = false; + goto check_type; + } + if (force_nl) { /* if we should insert a nl here, put it into + * the buffer */ + force_nl = false; + --line_no; /* this will be re-increased when the nl is + * read from the buffer */ + need_chars(save_com,2); + *save_com.end++ = '\n'; + *save_com.end++ = ' '; + if (verbose && !flushed_nl) /* print error msg if the line + * was not already broken */ + diag(0, "Line broken"); + flushed_nl = false; + } + for (t_ptr = token; t_ptr < token_end; ++t_ptr) + { + need_chars(save_com,1); + *save_com.end++ = *t_ptr; /* copy token into temp buffer */ + } + parser_state_tos->procname = "\0"; + + sw_buffer: + parser_state_tos->search_brace = false; /* stop looking for start of + * stmt */ + bp_save = buf_ptr; /* save current input buffer */ + be_save = buf_end; + buf_ptr = save_com.ptr; /* fix so that subsequent calls to + * lexi will take tokens out of + * save_com */ + need_chars(save_com,1); + *save_com.end++ = ' ';/* add trailing blank, just in case */ + buf_end = save_com.end; + save_com.end = save_com.ptr; /* make save_com empty */ + break; + } /* end of switch */ + if (type_code != 0) /* we must make this check, just in case there + * was an unexpected EOF */ + type_code = lexi(); /* read another token */ + /* if (parser_state_tos->search_brace) parser_state_tos->procname[0] = 0; */ + if ((is_procname = parser_state_tos->procname[0]) && flushed_nl + && !procnames_start_line && parser_state_tos->in_decl + && type_code == ident) + flushed_nl = 0; + } /* end of while (search_brace) */ + last_else = 0; +check_type: + if (type_code == 0) { /* we got eof */ + if (s_lab != e_lab || s_code != e_code + || s_com != e_com) /* must dump end of line */ + dump_line(); + if (parser_state_tos->tos > 1) /* check for balanced braces */ + diag(1, "Stuff missing from end of file."); + + if (verbose) { + printf("There were %d output lines and %d comments\n", + parser_state_tos->out_lines, parser_state_tos->out_coms); + printf("(Lines with comments)/(Lines with code): %6.3f\n", + (1.0 * parser_state_tos->com_lines) / code_lines); + } + fflush(output); + exit(found_err); + } + if ( + (type_code != comment) && + (type_code != newline) && + (type_code != preesc) && + (type_code != form_feed)) { + if (force_nl && + (type_code != semicolon) && + (type_code != lbrace || !btype_2)) { + /* we should force a broken line here */ + if (verbose && !flushed_nl) + diag(0, "Line broken"); + flushed_nl = false; + dump_line(); + parser_state_tos->want_blank = false; /* dont insert blank at line start */ + force_nl = false; + } + parser_state_tos->in_stmt = true; /* turn on flag which causes an extra level of + * indentation. this is turned off by a ; or + * '}' */ + if (s_com != e_com) { /* the turkey has embedded a comment + * in a line. fix it */ + *e_code++ = ' '; + for (t_ptr = s_com; *t_ptr; ++t_ptr) { + check_size(code); + *e_code++ = *t_ptr; + } + *e_code++ = ' '; + *e_code = '\0'; /* null terminate code sect */ + parser_state_tos->want_blank = false; + e_com = s_com; + } + } + else if (type_code != comment) /* preserve force_nl thru a comment */ + force_nl = false; /* cancel forced newline after newline, form + * feed, etc */ + + + + /*-----------------------------------------------------*\ + | do switch on type of token scanned | + \*-----------------------------------------------------*/ + check_size(code); + switch (type_code) { /* now, decide what to do with the token */ + + case form_feed: /* found a form feed in line */ + parser_state_tos->use_ff = true; /* a form feed is treated much like a newline */ + dump_line(); + parser_state_tos->want_blank = false; + break; + + case newline: + if (parser_state_tos->last_token != comma || parser_state_tos->p_l_follow > 0 + || !leave_comma || parser_state_tos->block_init || !break_comma || s_com != e_com) { + dump_line(); + parser_state_tos->want_blank = false; + } + ++line_no; /* keep track of input line number */ + break; + + case lparen: + /* Count parens so we know how deep we are. */ + if (++parser_state_tos->p_l_follow + >= parser_state_tos->paren_indents_size) + { + parser_state_tos->paren_indents_size *= 2; + parser_state_tos->paren_indents = (short *) + xrealloc (parser_state_tos->paren_indents, + parser_state_tos->paren_indents_size + * sizeof (short)); + } + if (parser_state_tos->want_blank && *token != '[' && + (parser_state_tos->last_token != ident || proc_calls_space + || (parser_state_tos->its_a_keyword && (!parser_state_tos->sizeof_keyword || Bill_Shannon)))) + *e_code++ = ' '; + if (parser_state_tos->in_decl && !parser_state_tos->block_init) + if (troff && !parser_state_tos->dumped_decl_indent && !is_procname && parser_state_tos->last_token == decl) { + parser_state_tos->dumped_decl_indent = 1; + sprintf (e_code, "\n.Du %dp+\200p \"%.*s\"\n", dec_ind * 7, + token_end - token, token); + e_code += strlen(e_code); + } + else { + while ((e_code - s_code) < dec_ind) { + check_size(code); + *e_code++ = ' '; + } + if (token_end > token+1) { + *e_code++ = token[0]; + *e_code++ = token[1]; + } else + *e_code++ = token[0]; + } + else { + if (token_end > token+1) { + *e_code++ = token[0]; + *e_code++ = token[1]; + } else + *e_code++ = token[0]; + } + parser_state_tos->paren_indents[parser_state_tos->p_l_follow - 1] = e_code - s_code; + if (sp_sw && parser_state_tos->p_l_follow == 1 && extra_expression_indent + && parser_state_tos->paren_indents[0] < 2 * ind_size) + parser_state_tos->paren_indents[0] = 2 * ind_size; + parser_state_tos->want_blank = false; + if (parser_state_tos->in_or_st && *token == '(' && parser_state_tos->tos <= 2) { + /* + * this is a kluge to make sure that declarations will be + * aligned right if proc decl has an explicit type on it, i.e. + * "int a(x) {..." + */ + parse(semicolon); /* I said this was a kluge... */ + parser_state_tos->in_or_st = false; /* turn off flag for structure decl or + * initialization */ + } + if (parser_state_tos->sizeof_keyword) + parser_state_tos->sizeof_mask |= 1 << parser_state_tos->p_l_follow; + break; + + case rparen: + if (parser_state_tos->cast_mask & (1 << parser_state_tos->p_l_follow) & ~parser_state_tos->sizeof_mask) { + parser_state_tos->last_u_d = true; + parser_state_tos->cast_mask &= (1 << parser_state_tos->p_l_follow) - 1; + } + parser_state_tos->sizeof_mask &= (1 << parser_state_tos->p_l_follow) - 1; + if (--parser_state_tos->p_l_follow < 0) { + parser_state_tos->p_l_follow = 0; + diag(0, "Extra %c", *token); + } + if (e_code == s_code) /* if the paren starts the line */ + { + parser_state_tos->paren_level = parser_state_tos->p_l_follow; /* then indent it */ + paren_target = -parser_state_tos->paren_indents[parser_state_tos->paren_level - 1]; + } + *e_code++ = token[0]; + if (token_end > token+1) + *e_code++ = token[1]; + parser_state_tos->want_blank = true; + + if (sp_sw && (parser_state_tos->p_l_follow == 0)) { /* check for end of if + * (...), or some such */ + last_token_ends_sp = 2; + sp_sw = false; + force_nl = true;/* must force newline after if */ + parser_state_tos->last_u_d = true; /* inform lexi that a following + * operator is unary */ + parser_state_tos->in_stmt = false; /* dont use stmt continuation + * indentation */ + + parse(hd_type); /* let parser worry about if, or whatever */ + } + parser_state_tos->search_brace = btype_2; /* this should insure that constructs + * such as main(){...} and int[]{...} + * have their braces put in the right + * place */ + break; + + case unary_op: /* this could be any unary operation */ + if (parser_state_tos->want_blank) + *e_code++ = ' '; + + if (troff && !parser_state_tos->dumped_decl_indent && parser_state_tos->in_decl && !is_procname) { + sprintf(e_code, "\n.Du %dp+\200p \"%.*s\"\n", dec_ind * 7, + token_end - token, token); + parser_state_tos->dumped_decl_indent = 1; + e_code += strlen(e_code); + } + else { + char *res = token; + char *res_end = token_end; + + if (parser_state_tos->in_decl && !parser_state_tos->block_init) { /* if this is a unary op + * in a declaration, we + * should indent this + * token */ + while ((e_code - s_code) < (dec_ind - (token_end-token))) { + check_size(code); + *e_code++ = ' '; /* pad it */ + } + } + if (troff && token[0] == '-' && token[1] == '>') + { + static char resval[] = "\\(->"; + res = resval; + res_end = res + sizeof(resval); + } + for (t_ptr = res; t_ptr < res_end; ++t_ptr) { + check_size(code); + *e_code++ = *t_ptr; + } + } + parser_state_tos->want_blank = false; + break; + + case binary_op: /* any binary operation */ + do_binary: + if (parser_state_tos->want_blank) + *e_code++ = ' '; + { + char *res = token; + char *res_end = token_end; +#define set_res(str) \ + {\ + static char resval[] = str;\ + res = resval;\ + res_end = res + sizeof(resval);\ + } + + if (troff) + switch (token[0]) { + case '<': + if (token[1] == '=') + set_res ("\\(<="); + break; + case '>': + if (token[1] == '=') + set_res ("\\(>="); + break; + case '!': + if (token[1] == '=') + set_res ("\\(!="); + break; + case '|': + if (token[1] == '|') + { + set_res ("\\(br\\(br"); + } + else if (token[1] == 0) + set_res ("\\(br"); + break; + } + for (t_ptr = res; t_ptr < res_end; ++t_ptr) { + check_size(code); + *e_code++ = *t_ptr; /* move the operator */ + } + } + parser_state_tos->want_blank = true; + break; + + case postop: /* got a trailing ++ or -- */ + *e_code++ = token[0]; + *e_code++ = token[1]; + parser_state_tos->want_blank = true; + break; + + case question: /* got a ? */ + squest++; /* this will be used when a later colon + * appears so we can distinguish the + * ?: construct */ + if (parser_state_tos->want_blank) + *e_code++ = ' '; + *e_code++ = '?'; + parser_state_tos->want_blank = true; + break; + + case casestmt: /* got word 'case' or 'default' */ + scase = true; /* so we can process the later colon properly */ + goto copy_id; + + case colon: /* got a ':' */ + if (squest > 0) { /* it is part of the ?: construct */ + --squest; + if (parser_state_tos->want_blank) + *e_code++ = ' '; + *e_code++ = ':'; + parser_state_tos->want_blank = true; + break; + } + if (parser_state_tos->in_decl) { + *e_code++ = ':'; + parser_state_tos->want_blank = false; + break; + } + parser_state_tos->in_stmt = false; /* seeing a label does not imply we are in a + * stmt */ + for (t_ptr = s_code; *t_ptr; ++t_ptr) + *e_lab++ = *t_ptr; /* turn everything so far into a label */ + e_code = s_code; + *e_lab++ = ':'; + *e_lab++ = ' '; + *e_lab = '\0'; + + force_nl = parser_state_tos->pcase = scase; /* parser_state_tos->pcase will be used by + * dump_line to decide how to + * indent the label. force_nl + * will force a case n: to be + * on a line by itself */ + scase = false; + parser_state_tos->want_blank = false; + break; + + case semicolon: /* got a ';' */ + parser_state_tos->in_or_st = false;/* we are not in an initialization or + * structure declaration */ + scase = false; /* these will only need resetting in a error */ + squest = 0; + /* The following code doesn't seem to do much good. + Just because we've found something like + extern int foo(); or + int (*foo)(); + doesn't mean we are out of a declaration. Now if it was + serving some purpose we'll have to address that.... + if (parser_state_tos->last_token == rparen) + parser_state_tos->in_parameter_declaration = 0; + */ + parser_state_tos->cast_mask = 0; + parser_state_tos->sizeof_mask = 0; + parser_state_tos->block_init = 0; + parser_state_tos->block_init_level = 0; + parser_state_tos->just_saw_decl--; + + if (parser_state_tos->in_decl && s_code == e_code && !parser_state_tos->block_init) + while ((e_code - s_code) < (dec_ind - 1)) { + check_size(code); + *e_code++ = ' '; + } + + parser_state_tos->in_decl = (parser_state_tos->dec_nest > 0); /* if we were in a first level + * structure declaration, we + * arent any more */ + + if ((!sp_sw || hd_type != forstmt) && parser_state_tos->p_l_follow > 0) { + + /* + * This should be true iff there were unbalanced parens in the + * stmt. It is a bit complicated, because the semicolon might + * be in a for stmt + */ + diag(1, "Unbalanced parens (1)"); + parser_state_tos->p_l_follow = 0; + if (sp_sw) { /* this is a check for a if, while, etc. with + * unbalanced parens */ + sp_sw = false; + parse(hd_type); /* dont lose the if, or whatever */ + } + } + + /* If we have a semicolon following an if, while, or for, + and the user wants us to, we should insert a space + (to show that there is a null statement there). */ + if (last_token_ends_sp && space_sp_semicolon) + { + *e_code++ = ' '; + } + *e_code++ = ';'; + parser_state_tos->want_blank = true; + parser_state_tos->in_stmt = (parser_state_tos->p_l_follow > 0); /* we are no longer in the + * middle of a stmt */ + + if (!sp_sw) { /* if not if for (;;) */ + parse(semicolon); /* let parser know about end of stmt */ + force_nl = true;/* force newline after a end of stmt */ + } + break; + + case lbrace: /* got a '{' */ + parser_state_tos->in_stmt = false; /* dont indent the {} */ + if (!parser_state_tos->block_init) + force_nl = true;/* force other stuff on same line as '{' onto + * new line */ + else if (parser_state_tos->block_init_level <= 0) + parser_state_tos->block_init_level = 1; + else + parser_state_tos->block_init_level++; + + if (s_code != e_code && !parser_state_tos->block_init) { + if (!btype_2) { + dump_line(); + parser_state_tos->want_blank = false; + } + else if (parser_state_tos->in_parameter_declaration && !parser_state_tos->in_or_st) { + parser_state_tos->i_l_follow = 0; + dump_line(); + parser_state_tos->want_blank = false; + } + } + if (parser_state_tos->in_parameter_declaration) + prefix_blankline_requested = 0; + + if (parser_state_tos->p_l_follow > 0) { /* check for preceeding unbalanced + * parens */ + diag(1, "Unbalanced parens (2)"); + parser_state_tos->p_l_follow = 0; + if (sp_sw) { /* check for unclosed if, for, etc. */ + sp_sw = false; + parse(hd_type); + parser_state_tos->ind_level = parser_state_tos->i_l_follow; + } + } + if (s_code == e_code) + parser_state_tos->ind_stmt = false; /* dont put extra indentation on line + * with '{' */ + if (parser_state_tos->in_decl && parser_state_tos->in_or_st) { /* this is either a structure + * declaration or an init */ + di_stack[parser_state_tos->dec_nest++] = dec_ind; + /* ? dec_ind = 0; */ + } + else { + parser_state_tos->decl_on_line = false; /* we cant be in the middle of + * a declaration, so dont do + * special indentation of + * comments */ + if (blanklines_after_declarations_at_proctop + && parser_state_tos->in_parameter_declaration) + postfix_blankline_requested = 1; + parser_state_tos->in_parameter_declaration = 0; + } + dec_ind = 0; + parse(lbrace); /* let parser know about this */ + if (!(lpc && e_code[-1] == '(')) + if (parser_state_tos->want_blank) /* put a blank before '{' if '{' is not at + * start of line */ + *e_code++ = ' '; + parser_state_tos->want_blank = false; + *e_code++ = '{'; + parser_state_tos->just_saw_decl = 0; + break; + + case rbrace: /* got a '}' */ + if (parser_state_tos->p_stack[parser_state_tos->tos] == decl && !parser_state_tos->block_init) /* semicolons can be + * omitted in + * declarations */ + parse(semicolon); + if (parser_state_tos->p_l_follow) {/* check for unclosed if, for, else. */ + diag(1, "Unbalanced parens (3)"); + parser_state_tos->p_l_follow = 0; + sp_sw = false; + } + parser_state_tos->just_saw_decl = 0; + parser_state_tos->block_init_level--; + if (s_code != e_code && !parser_state_tos->block_init) { /* '}' must be first on + * line */ + if (verbose) + diag(0, "Line broken"); + dump_line(); + } + *e_code++ = '}'; + parser_state_tos->want_blank = true; + parser_state_tos->in_stmt = parser_state_tos->ind_stmt = false; + if (parser_state_tos->dec_nest > 0) { /* we are in multi-level structure + * declaration */ + dec_ind = di_stack[--parser_state_tos->dec_nest]; + if (parser_state_tos->dec_nest == 0 && !parser_state_tos->in_parameter_declaration) + parser_state_tos->just_saw_decl = 2; + parser_state_tos->in_decl = true; + } + prefix_blankline_requested = 0; + parse(rbrace); /* let parser know about this */ + parser_state_tos->search_brace = cuddle_else && parser_state_tos->p_stack[parser_state_tos->tos] == ifhead + && parser_state_tos->il[parser_state_tos->tos] >= parser_state_tos->ind_level; + if (parser_state_tos->tos <= 1 && blanklines_after_procs && parser_state_tos->dec_nest <= 0) + postfix_blankline_requested = 1; + break; + + case swstmt: /* got keyword "switch" */ + sp_sw = true; + hd_type = swstmt; /* keep this for when we have seen the + * expression */ + goto copy_id; /* go move the token into buffer */ + + case sp_paren: /* token is if, while, for */ + sp_sw = true; /* the interesting stuff is done after the + * expression is scanned */ + hd_type = (*token == 'i' ? ifstmt : + (*token == 'w' ? whilestmt : forstmt)); + + /* + * remember the type of header for later use by parser + */ + goto copy_id; /* copy the token into line */ + + case sp_nparen: /* got else, do */ + parser_state_tos->in_stmt = false; + if (*token == 'e') { + if (e_code != s_code && (!cuddle_else || e_code[-1] != '}')) { + if (verbose) + diag(0, "Line broken"); + dump_line();/* make sure this starts a line */ + parser_state_tos->want_blank = false; + } + force_nl = true;/* also, following stuff must go onto new line */ + last_else = 1; + parse(elselit); + } + else { + if (e_code != s_code) { /* make sure this starts a line */ + if (verbose) + diag(0, "Line broken"); + dump_line(); + parser_state_tos->want_blank = false; + } + force_nl = true;/* also, following stuff must go onto new line */ + last_else = 0; + parse(dolit); + } + goto copy_id; /* move the token into line */ + + case decl: /* we have a declaration type (int, register, + * etc.) */ + parse(decl); /* let parser worry about indentation */ + if (parser_state_tos->last_token == rparen && parser_state_tos->tos <= 1) { + parser_state_tos->in_parameter_declaration = 1; + if (s_code != e_code) { + dump_line(); + parser_state_tos->want_blank = 0; + } + } + if (parser_state_tos->in_parameter_declaration && indent_parameters && parser_state_tos->dec_nest == 0) { + parser_state_tos->ind_level = parser_state_tos->i_l_follow = indent_parameters; + parser_state_tos->ind_stmt = 0; + } + parser_state_tos->in_or_st = true; /* this might be a structure or initialization + * declaration */ + parser_state_tos->in_decl = parser_state_tos->decl_on_line = true; + if ( /* !parser_state_tos->in_or_st && */ parser_state_tos->dec_nest <= 0) + parser_state_tos->just_saw_decl = 2; + prefix_blankline_requested = 0; + i = token_end - token + 1; /* get length of token plus 1 */ + + /* + * dec_ind = e_code - s_code + (parser_state_tos->decl_indent>i ? parser_state_tos->decl_indent + * : i); + */ + dec_ind = decl_indent > 0 ? decl_indent : i; + goto copy_id; + + case ident: /* got an identifier or constant */ + if (parser_state_tos->in_decl) { /* if we are in a declaration, we must indent + * identifier */ + if (parser_state_tos->want_blank) + *e_code++ = ' '; + parser_state_tos->want_blank = false; + if (is_procname == 0 || !procnames_start_line) { + if (!parser_state_tos->block_init) + if (troff && !parser_state_tos->dumped_decl_indent) { + sprintf(e_code, "\n.De %dp+\200p\n", dec_ind * 7); + parser_state_tos->dumped_decl_indent = 1; + e_code += strlen(e_code); + } + else + while ((e_code - s_code) < dec_ind) { + check_size(code); + *e_code++ = ' '; + } + } + else { + if (dec_ind && s_code != e_code) + dump_line(); + dec_ind = 0; + parser_state_tos->want_blank = false; + } + } + else if (sp_sw && parser_state_tos->p_l_follow == 0) { + sp_sw = false; + force_nl = true; + parser_state_tos->last_u_d = true; + parser_state_tos->in_stmt = false; + parse(hd_type); + } + copy_id: + if (parser_state_tos->want_blank) + *e_code++ = ' '; + if (troff && parser_state_tos->its_a_keyword) { + e_code = chfont(&bodyf, &keywordf, e_code); + for (t_ptr = token; t_ptr < token_end; ++t_ptr) { + check_size(code); + *e_code++ = keywordf.allcaps && islower(*t_ptr) + ? toupper(*t_ptr) : *t_ptr; + } + e_code = chfont(&keywordf, &bodyf, e_code); + } + else + { + /* Troff mode requires that strings be processed specially. */ + if (troff && (*token == '"' || *token == '\'')) + { + char qchar; + + qchar = *token; + *e_code++ = '`'; + if (qchar == '"') + *e_code++ = '`'; + e_code = chfont(&bodyf, &stringf, e_code); + + t_ptr = token + 1; + while (t_ptr < token_end) + { + *e_code = *t_ptr++; + if (*e_code == '\\') + { + *++e_code = '\\'; + if (*t_ptr == '\\') + *++e_code = '\\'; + /* Copy char after backslash. */ + *++e_code = *t_ptr++; + /* Point after the last char we copied. */ + e_code++; + } + } + e_code = chfont(&stringf, &bodyf, e_code - 1); + if (qchar == '"') + *e_code++ = '\''; + } + else + for (t_ptr = token; t_ptr < token_end; ++t_ptr) + { + check_size(code); + *e_code++ = *t_ptr; + } + } + parser_state_tos->want_blank = true; + + /* If the token is va_dcl, it appears without a semicolon, + so we need to pretend that one was there. */ + if ((token_end - token) == 6 + && strncmp(token,"va_dcl",6) == 0) + { + parser_state_tos->in_or_st = false; + parser_state_tos->just_saw_decl--; + parser_state_tos->in_decl = 0; + parse(semicolon); + force_nl = true; + } + break; + + case period: /* treat a period kind of like a binary + * operation */ + *e_code++ = '.'; /* move the period into line */ + parser_state_tos->want_blank = false; /* dont put a blank after a period */ + break; + + case comma: + parser_state_tos->want_blank = (s_code != e_code); /* only put blank after comma + * if comma does not start the + * line */ + if (parser_state_tos->in_decl && is_procname == 0 && !parser_state_tos->block_init) + while ((e_code - s_code) < (dec_ind - 1)) { + check_size(code); + *e_code++ = ' '; + } + + *e_code++ = ','; + if (parser_state_tos->p_l_follow == 0) { + if (parser_state_tos->block_init_level <= 0) + parser_state_tos->block_init = 0; + if (break_comma && !leave_comma) + force_nl = true; + } + break; + + case preesc: /* got the character '#' */ + if ((s_com != e_com) || + (s_lab != e_lab) || + (s_code != e_code)) + dump_line(); + *e_lab++ = '#'; /* move whole line to 'label' buffer */ + { + int in_comment = 0; + int com_start = 0; + char quote = 0; + int com_end = 0; + + while (*buf_ptr != '\n' || in_comment) { + check_size(lab); + *e_lab = *buf_ptr++; + if (buf_ptr >= buf_end) + fill_buffer(); + switch (*e_lab++) { + case BACKSLASH: + if (troff) + *e_lab++ = BACKSLASH; + if (!in_comment) { + *e_lab++ = *buf_ptr++; + if (buf_ptr >= buf_end) + fill_buffer(); + } + break; + case '/': + if (*buf_ptr == '*' && !in_comment && !quote) { + in_comment = 1; + *e_lab++ = *buf_ptr++; + com_start = e_lab - s_lab - 2; + } + break; + case '"': + if (quote == '"') + quote = 0; + break; + case '\'': + if (quote == '\'') + quote = 0; + break; + case '*': + if (*buf_ptr == '/' && in_comment) { + in_comment = 0; + *e_lab++ = *buf_ptr++; + com_end = e_lab - s_lab; + } + break; + } + } + + while (e_lab > s_lab && (e_lab[-1] == ' ' || e_lab[-1] == '\t')) + e_lab--; + if (e_lab - s_lab == com_end && bp_save == 0) { /* comment on + * preprocessor line */ + if (save_com.end != save_com.ptr) + { + need_chars(save_com,2); + *save_com.end++ = '\n'; /* add newline between + * comments */ + *save_com.end++ = ' '; + --line_no; + } + need_chars(save_com,com_end - com_start); + strncpy (save_com.end, s_lab + com_start, + com_end - com_start); + save_com.end += com_end - com_start; + + e_lab = s_lab + com_start; + while (e_lab > s_lab && (e_lab[-1] == ' ' || e_lab[-1] == '\t')) + e_lab--; + bp_save = buf_ptr; /* save current input buffer */ + be_save = buf_end; + buf_ptr = save_com.ptr; /* fix so that subsequent calls to + * lexi will take tokens out of + * save_com */ + need_chars(save_com,1); + *save_com.end++ = ' '; /* add trailing blank, just in case */ + buf_end = save_com.end; + save_com.end = save_com.ptr; /* make save_com empty */ + } + *e_lab = '\0'; /* null terminate line */ + parser_state_tos->pcase = false; + } + + if (strncmp(s_lab, "#if", 3) == 0) { + if (blanklines_around_conditional_compilation) { + register c; + prefix_blankline_requested++; + while ((c = *in_prog_pos++) == '\n'); + in_prog_pos--; + } + { + /* Push a copy of the parser_state onto the stack. + All manipulations will use the copy at the top of stack, + and then we + can return to the previous state by popping the + stack. */ + struct parser_state *new; + + new = (struct parser_state *) + xmalloc(sizeof(struct parser_state)); + memcpy (new, parser_state_tos, sizeof(struct parser_state)); + + /* We need to copy the dynamically allocated arrays in + the struct parser_state too. */ + new->p_stack = (enum codes *) + xmalloc (parser_state_tos->p_stack_size + * sizeof (enum codes)); + memcpy (new->p_stack, parser_state_tos->p_stack, + parser_state_tos->p_stack_size * sizeof (enum codes)); + + new->il = (int *) + xmalloc (parser_state_tos->p_stack_size * sizeof (int)); + memcpy (new->il, parser_state_tos->il, + parser_state_tos->p_stack_size * sizeof (int)); + + new->cstk = (int *) + xmalloc (parser_state_tos->p_stack_size + * sizeof (int)); + memcpy (new->cstk, parser_state_tos->cstk, + parser_state_tos->p_stack_size * sizeof (int)); + + new->paren_indents = (short *)xmalloc + (parser_state_tos->paren_indents_size * sizeof (short)); + memcpy (new->paren_indents, parser_state_tos->paren_indents, + parser_state_tos->paren_indents_size * sizeof (short)); + + new->next = parser_state_tos; + parser_state_tos = new; + } + } + else if (strncmp(s_lab, "#else", 5) == 0) + { + /* When we get #else, we want to restore the parser + state to what it was before the matching #if, so + that things get lined up with the code before the + #if. However, we do not want to pop the stack; we + just want to copy the second to top elt of the + stack because when we encounter the #endif, it will + pop the stack. */ + else_or_endif = true; + if (parser_state_tos->next) + { + /* First save the addresses of the arrays + for the top of stack. */ + enum codes *tos_p_stack = parser_state_tos->p_stack; + int *tos_il = parser_state_tos->il; + int *tos_cstk = parser_state_tos->cstk; + short *tos_paren_indents = + parser_state_tos->paren_indents; + struct parser_state *second = + parser_state_tos->next; + + memcpy (parser_state_tos, second, + sizeof(struct parser_state)); + parser_state_tos->next = second; + + /* Now copy the arrays from the second to top of + stack to the top of stack. */ + /* Since the p_stack, etc. arrays only grow, never + shrink, we know that they will be big enough to + fit the array from the second to top of stack. */ + parser_state_tos->p_stack = tos_p_stack; + memcpy (parser_state_tos->p_stack, + parser_state_tos->next->p_stack, + parser_state_tos->p_stack_size + * sizeof (enum codes)); + + parser_state_tos->il = tos_il; + memcpy (parser_state_tos->il, + parser_state_tos->next->il, + parser_state_tos->p_stack_size * sizeof (int)); + + parser_state_tos->cstk = tos_cstk; + memcpy (parser_state_tos->cstk, + parser_state_tos->next->cstk, + parser_state_tos->p_stack_size * sizeof (int)); + + parser_state_tos->paren_indents = tos_paren_indents; + memcpy (parser_state_tos->paren_indents, + parser_state_tos->next->paren_indents, + parser_state_tos->paren_indents_size + * sizeof (short)); + } + else + diag(1, "Unmatched #else"); + } + else if (strncmp(s_lab, "#endif", 6) == 0) + { + else_or_endif = true; + /* We want to remove the second to top elt on the + stack, which was put there by #if and was used to + restore the stack at the #else (if there was one). + We want to leave the top of stack + unmolested so that the state which we have been + using is unchanged. */ + if (parser_state_tos->next) + { + struct parser_state *second = parser_state_tos->next; + + parser_state_tos->next = second->next; + free (second->p_stack); + free (second->il); + free (second->cstk); + free (second->paren_indents); + free (second); + } + else + diag(1, "Unmatched #endif"); + if (blanklines_around_conditional_compilation) { + postfix_blankline_requested++; + n_real_blanklines = 0; + } + } + break; /* subsequent processing of the newline + * character will cause the line to be printed */ + + case comment: /* we have gotten a '/ *' this is a biggie */ + proc_comment: + if (flushed_nl) { /* we should force a broken line here */ + flushed_nl = false; + dump_line(); + parser_state_tos->want_blank = false; /* dont insert blank at line start */ + force_nl = false; + } + pr_comment(); + break; + } /* end of big switch stmt */ + + *e_code = '\0'; /* make sure code section is null terminated */ + if (type_code != comment && type_code != newline && type_code != preesc) + parser_state_tos->last_token = type_code; + + } /* end of main while (1) loop */ +} + +/* + * copy input file to backup file if in_name is /blah/blah/blah/file, then + * backup file will be "file.BAK" then make the backup file the input and + * original input file the output + */ +bakcopy() +{ + /* file descriptor for the output file */ + int bakchn; + + /* Used to walk around file names */ + register char *p; + + /* Buffer for error message. */ + char *errbuf; + /* Backup file name. */ + char *bakfile; + + /* construct name of backup file */ + for (p = in_name; *p; p++); /* skip to end of string */ + while (p > in_name && *p != '/') /* find last '/' */ + p--; + if (*p == '/') + p++; + bakfile = xmalloc(40 + strlen(p)); +#ifndef MSDOS + sprintf(bakfile, "%s.BAK", p); +#else + { + char *here; + + if ((here = strchr(p,'.')) == NULL || here <= p) + sprintf(bakfile,"%s.BAK",p); + else { + *here = 0; + sprintf(bakfile,"%s.BAK",p); + *here = '.'; + } + } +#endif + errbuf = xmalloc(80 + strlen(p)); + + sprintf(errbuf,"indent: %s",bakfile); + + /* copy in_name to backup file */ + bakchn = creat(bakfile, 0600); + if (bakchn < 0) + { + perror(errbuf); + exit(1); + } + + if (write(bakchn, in_prog, in_prog_size) != in_prog_size) + { + perror(errbuf); + exit(1); + } + + close(bakchn); + + /* now the original input file will be the output */ + output = fopen(in_name, "w"); + if (output == 0) { + fprintf(stderr, "indent: can't create %s\n", in_name); + unlink(bakfile); + exit(1); + } + free (errbuf); + free (bakfile); +} diff --git a/src/util/indent/indent_globs.h b/src/util/indent/indent_globs.h new file mode 100644 index 0000000..a46b34c --- /dev/null +++ b/src/util/indent/indent_globs.h @@ -0,0 +1,406 @@ +/* + * Copyright (c) 1985 Sun Microsystems, Inc. + * Copyright (c) 1980 The Regents of the University of California. + * Copyright (c) 1976 Board of Trustees of the University of Illinois. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley, the University of Illinois, + * Urbana, and Sun Microsystems, Inc. The name of either University + * or Sun Microsystems may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * @(#)indent_globs.h 5.7 (Berkeley) 9/15/88 + */ + +#include +#include +/* Do the same thing, but abort with an error if out of memory + (see globs.c). */ +char *xmalloc (); +char *xrealloc (); + +#ifndef M_UNIX +#include +#else +#include +#endif + +#define BACKSLASH '\\' +#define label_offset 2 /* number of levels a label is placed to left + * of code */ +/* Initial size of internal buffers (they are extended as necessary). */ +#define bufsize 1000 + +#define tabsize 8 /* the size of a tab */ +#define tabmask 0177770 /* mask used when figuring length of lines + * with tabs */ + +enum codes {code_eof = 0, /* end of file */ + newline, + lparen, /* '(' or '['. Also '{' in an initialization. */ + rparen, /* ')' or ']'. Also '}' in an initialization. */ + unary_op, binary_op, postop, + question, casestmt, colon, semicolon, lbrace, rbrace, + ident, /* string or char literal, identifier, number */ + comma, comment, swstmt, + preesc, /* '#'. */ + form_feed, decl, + sp_paren, /* if, for, or while token */ + sp_nparen, ifstmt, whilestmt, + forstmt, stmt, stmtl, elselit, dolit, dohead, ifhead, + elsehead, period }; + +#define false 0 +#define true 1 + +#ifdef MAIN +#define GLOBAL +#else /* !MAIN */ +#define GLOBAL extern +#endif /* MAIN */ + +/* Name of input file. */ +extern char *in_name; + +GLOBAL char *in_prog; /* pointer to the null-terminated input program */ + +/* Point to the position in the input program which we are currently + looking at. */ +GLOBAL char *in_prog_pos; + +/* Point to the start of the current line. */ +GLOBAL char *cur_line; + +/* Size of the input program, not including the ' \n\0' we add at the end */ +GLOBAL int in_prog_size; + +GLOBAL FILE *output; /* the output file */ + +/* The following macro employs traditional token-pasting. If one desires + to make this thing run without giving gcc the -traditional option + or it becomes inconvenient, it should be rewritten to use a struct + for each buffer (along the lines of the 'struct buf' later in this + file). */ +#ifdef __STDC__ +#define paste(a, b) a ## b +#else +#define paste(a, b) a/**/b +#endif +#define check_size(name) \ + if (paste(e_,name) >= paste(l_,name)) { \ + register nsize = paste(l_,name)-paste(s_,name)+400; \ + paste(name,buf) = (char *) xrealloc(paste(name,buf), nsize); \ + paste(e_,name) = paste(name,buf) + \ + (paste(e_,name)-paste(s_,name)) + 1; \ + paste(l_,name) = paste(name,buf) + nsize - 5; \ + paste(s_,name) = paste(name,buf) + 1; \ + } + +GLOBAL char *labbuf; /* buffer for label */ +GLOBAL char *s_lab; /* start ... */ +GLOBAL char *e_lab; /* .. and end of stored label */ +GLOBAL char *l_lab; /* limit of label buffer */ + +GLOBAL char *codebuf; /* buffer for code section */ +GLOBAL char *s_code; /* start ... */ +GLOBAL char *e_code; /* .. and end of stored code */ +GLOBAL char *l_code; /* limit of code section */ + +GLOBAL char *combuf; /* buffer for comments */ +GLOBAL char *s_com; /* start ... */ +GLOBAL char *e_com; /* ... and end of stored comments */ +GLOBAL char *l_com; /* limit of comment buffer */ + +GLOBAL char *buf_ptr; /* ptr to next character to be taken from + * in_buffer */ +GLOBAL char *buf_end; /* ptr to first after last char in in_buffer */ + +/* pointer to the token that lexi() has just found */ +GLOBAL char *token; +/* points to the first char after the end of token */ +GLOBAL char *token_end; + +/* Used to keep track of buffers. */ +struct buf { + char *ptr; /* points to the start of the buffer */ + char *end; /* points to the character beyond the last one (e.g. is equal + to ptr if the buffer is empty). */ + int size; /* how many chars are currently allocated. */ +}; +/* Insure that BUFSTRUC has at least REQ more chars left, if not extend it. + Note: This may change bufstruc.ptr. */ +#define need_chars(bufstruc, req) \ + if ((bufstruc.end - bufstruc.ptr + (req)) >= bufstruc.size) \ + {\ + int cur_chars = bufstruc.end - bufstruc.ptr;\ + bufstruc.size *= 2;\ + bufstruc.ptr = xrealloc(bufstruc.ptr,bufstruc.size);\ + bufstruc.end = bufstruc.ptr + cur_chars;\ + } +/* Initialize BUFSTRUC. */ +#define init_buf(bufstruc) \ + bufstruc.end = bufstruc.ptr = xmalloc(bufsize),\ + bufstruc.size = bufsize + +/* Buffer in which to save a comment which occurs between an if(), while(), + etc., and the statement following it. Note: the fact that we point + into this buffer, and that we might realloc() it (via the + need_chars macro) is a bad thing (since when the buffer is + realloc'd its address might change, making any pointers into it + point to garbage), but since the filling of the buffer (hence the + need_chars) and the using of the buffer (where buf_ptr points into + it) occur at different times, we can get away with it (it would not + be trivial to fix). */ +GLOBAL struct buf save_com; + +GLOBAL char *bp_save; /* saved value of buf_ptr when taking input + * from save_com */ +GLOBAL char *be_save; /* similarly saved value of buf_end */ + + +GLOBAL int pointer_as_binop; +GLOBAL int blanklines_after_declarations; +GLOBAL int blanklines_before_blockcomments; +extern int blanklines_after_procs; +GLOBAL int blanklines_around_conditional_compilation; +GLOBAL int swallow_optional_blanklines; +GLOBAL int n_real_blanklines; +GLOBAL int prefix_blankline_requested; +GLOBAL int postfix_blankline_requested; +GLOBAL int break_comma; /* when true and not in parens, break after a + * comma */ + +/* number of spaces to indent braces from the suround if, while, etc. + in -bl (bype_2 == 0) code */ +GLOBAL int brace_indent; + +GLOBAL int btype_2; /* when true, brace should be on same line as + * if, while, etc */ +/* If true, a space is inserted between if, while, or for, and a semicolon + for example + while (*p++ == ' ') ; + */ +GLOBAL int space_sp_semicolon; + +/* True if a #else or #endif has been encountered. */ +extern int else_or_endif; + +GLOBAL int case_ind; /* indentation level to be used for a "case + * n:" in spaces */ +GLOBAL int code_lines; /* count of lines with code */ +GLOBAL int had_eof; /* set to true when input is exhausted */ +GLOBAL int line_no; /* the current line number. */ +GLOBAL int max_col; /* the maximum allowable line length */ +GLOBAL int verbose; /* when true, non-essential error messages are + * printed */ +GLOBAL int cuddle_else; /* true if else should cuddle up to '}' */ +GLOBAL int star_comment_cont; /* true iff comment continuation lines should + * have stars at the beginning of each line. */ +GLOBAL int comment_delimiter_on_blankline; +GLOBAL int troff; /* true iff were generating troff input */ +GLOBAL int procnames_start_line;/* if true, the names of procedures + * being defined get placed in column + * 1 (ie. a newline is placed between + * the type of the procedure and its + * name) */ +GLOBAL int proc_calls_space; /* If true, procedure calls look like: + * foo(bar) rather than foo (bar) */ +GLOBAL int format_col1_comments;/* If comments which start in column 1 + * are to be magically reformatted */ +/* If any comments are to be reformatted */ +GLOBAL int format_comments; + +extern int suppress_blanklines;/* set iff following blanklines should be + * suppressed */ +GLOBAL int continuation_indent; /* set to the indentation between the edge of + * code and continuation lines in spaces */ +GLOBAL int lineup_to_parens; /* if true, continued code within parens will + * be lined up to the open paren */ + +/* The position that we will line the current line up with when it + comes time to print it (if we are lining up to parentheses). */ +extern int paren_target; + +GLOBAL int Bill_Shannon; /* true iff a blank should always be inserted + * after sizeof */ +GLOBAL int blanklines_after_declarations_at_proctop; /* This is vaguely + * similar to + * blanklines_after_decla + * rations except that + * it only applies to + * the first set of + * declarations in a + * procedure (just after + * the first '{') and it + * causes a blank line + * to be generated even + * if there are no + * declarations */ +GLOBAL int block_comment_max_col; +GLOBAL int extra_expression_indent; /* True if continuation lines from the + * expression part of "if(e)", + * "while(e)", "for(e;e;e)" should be + * indented an extra tab stop so that + * they don't conflict with the code + * that follows */ + +extern int lpc; + +/* The following are all controlled by command line switches + (as are some of the things above). */ +extern int leave_comma; /* if true, never break declarations after + * commas */ +extern int decl_com_ind; /* the column in which comments after + * declarations should be put */ +extern int case_indent; /* The distance to indent case labels from the + * switch statement */ +extern int com_ind; /* the column in which comments to the right + * of code should start */ +extern int decl_indent; /* column to indent declared identifiers to */ +extern int ljust_decl; /* true if declarations should be left + * justified */ +extern int unindent_displace; /* comments not to the right of code + * will be placed this many + * indentation levels to the left of + * code */ +extern int else_if; /* True iff else if pairs should be handled + * specially */ +/* Number of spaces to indent parameters. */ +extern int indent_parameters; +/* The size of one indentation level in spaces. */ +extern int ind_size; + +/* -troff font state information */ + +struct fstate { + char font[4]; + char size; + int allcaps:1; +}; +char *chfont(); + +GLOBAL struct fstate + keywordf, /* keyword font */ + stringf, /* string font */ + boxcomf, /* Box comment font */ + blkcomf, /* Block comment font */ + scomf, /* Same line comment font */ + bodyf; /* major body font */ + +/* Initial size for the parser's stacks. (p_stack, il, and cstk). */ +#define INITIAL_STACK_SIZE 2 + +struct parser_state { + struct parser_state *next; + enum codes last_token; + struct fstate cfont; /* Current font */ + + /* This is the parsers stack, and the current allocated size. */ + enum codes *p_stack; + int p_stack_size; + + /* This stack stores indentation levels */ + /* Currently allocated size is stored in p_stack_size. */ + int *il; + + /* Used to store case stmt indentation levels. */ + /* Currently allocated size is stored in p_stack_size. */ + int *cstk; + + /* Pointer to the top of stack of the p_stack, il and cstk arrays. */ + int tos; + + int box_com; /* set to true when we are in a "boxed" + * comment. In that case, the first non-blank + * char should be lined up with the / in '/ *' */ + int comment_delta, + n_comment_delta; + int cast_mask; /* indicates which close parens close off + * casts */ + int sizeof_mask; /* indicates which close parens close off + * sizeof''s */ + int block_init; /* true iff inside a block initialization */ + int block_init_level; /* The level of brace nesting in an + * initialization */ + int last_nl; /* this is true if the last thing scanned was + * a newline */ + int in_or_st; /* Will be true iff there has been a + * declarator (e.g. int or char) and no left + * paren since the last semicolon. When true, + * a '{' is starting a structure definition or + * an initialization list */ + int bl_line; /* set to 1 by dump_line if the line is blank */ + int col_1; /* set to true if the last token started in + * column 1 */ + int com_col; /* this is the column in which the current + * coment should start */ + int com_lines; /* the number of lines with comments, set by + * dump_line */ + int dec_nest; /* current nesting level for structure or init */ + int decl_on_line; /* set to true if this line of code has part + * of a declaration on it */ + int i_l_follow; /* the level in spaces to which ind_level should be set + * after the current line is printed */ + int in_decl; /* set to true when we are in a declaration + * stmt. The processing of braces is then + * slightly different */ + int in_stmt; /* set to 1 while in a stmt */ + int ind_level; /* the current indentation level in spaces */ + int ind_stmt; /* set to 1 if next line should have an extra + * indentation level because we are in the + * middle of a stmt */ + int last_u_d; /* set to true after scanning a token which + * forces a following operator to be unary */ + int out_coms; /* the number of comments processed, set by + * pr_comment */ + int out_lines; /* the number of lines written, set by + * dump_line */ + int p_l_follow; /* used to remember how to indent following + * statement */ + int paren_level; /* parenthesization level. used to indent + * within stmts */ + /* Column positions of paren at each level. If positive, it + contains just the number of characters of code on the line up to + and including the right parenthesis character. If negative, it + contains the opposite of the actual level of indentation in + characters (that is, the indentation of the line has been added + to the number of characters and the sign has been reversed to + indicate that this has been done). */ + short *paren_indents; /* column positions of each paren */ + int paren_indents_size; /* Currently allocated size. */ + + int pcase; /* set to 1 if the current line label is a + * case. It is printed differently from a + * regular label */ + int search_brace; /* set to true by parse when it is necessary + * to buffer up all info up to the start of a + * stmt after an if, while, etc */ + int use_ff; /* set to one if the current line should be + * terminated with a form feed */ + int want_blank; /* set to true when the following token should + * be prefixed by a blank. (Said prefixing is + * ignored in some cases.) */ + int its_a_keyword; + int sizeof_keyword; + int dumped_decl_indent; + int in_parameter_declaration; + char *procname; /* The name of the current procedure */ + char *procname_end; /* One char past the last one in procname */ + int just_saw_decl; +}; +/* All manipulations of the parser stack occur at the tos + (via the macro ps). The elements of the stack below it are kept in + a linked list via the next field. */ +extern struct parser_state *parser_state_tos; + +/* The column in which comments to the right of #else and #endif should + start. */ +extern int else_endif_col; diff --git a/src/util/indent/io.c b/src/util/indent/io.c new file mode 100644 index 0000000..b9e8da4 --- /dev/null +++ b/src/util/indent/io.c @@ -0,0 +1,717 @@ +/* + * Copyright (c) 1985 Sun Microsystems, Inc. + * Copyright (c) 1980 The Regents of the University of California. + * Copyright (c) 1976 Board of Trustees of the University of Illinois. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley, the University of Illinois, + * Urbana, and Sun Microsystems, Inc. The name of either University + * or Sun Microsystems may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifndef lint +static char sccsid[] = "@(#)io.c 5.10 (Berkeley) 9/15/88"; +#endif /* not lint */ + +#include "indent_globs.h" +#include +/* POSIX says that fcntl.h should exist. Linking either sys/fcntl.h + or sys/file.h to fcntl.h should work fine if you don't have fcntl.h */ +#include + +#include +#include + +int suppress_blanklines = 0; +int comment_open; + +int paren_target; + +/* true if INDENT OFF is in effect */ +static int inhibit_formatting; + +dump_line() +{ /* dump_line is the routine that actually + * effects the printing of the new source. It + * prints the label section, followed by the + * code section with the appropriate nesting + * level, followed by any comments */ + register int cur_col, + target_col; + static not_first_line; + + if (parser_state_tos->procname[0]) { + if (troff) { + if (comment_open) { + comment_open = 0; + fprintf(output, ".*/\n"); + } + fprintf(output, ".Pr \"%.*s\"\n", parser_state_tos->procname_end - parser_state_tos->procname, + parser_state_tos->procname); + } + parser_state_tos->ind_level = 0; + parser_state_tos->procname = "\0"; + } + if (s_code == e_code && s_lab == e_lab && s_com == e_com) { + /* If we have a formfeed on a blank line, we should just output it, + rather than treat it as a normal blank line. */ + if (parser_state_tos->use_ff) + { + putc('\014',output); + parser_state_tos->use_ff = false; + } + else + { + if (suppress_blanklines > 0) + suppress_blanklines--; + else { + parser_state_tos->bl_line = true; + n_real_blanklines++; + } + } + } + else if (!inhibit_formatting) { + suppress_blanklines = 0; + parser_state_tos->bl_line = false; + if (prefix_blankline_requested && not_first_line) + if (swallow_optional_blanklines) { + if (n_real_blanklines == 1) + n_real_blanklines = 0; + } + else { + if (n_real_blanklines == 0) + n_real_blanklines = 1; + } + while (--n_real_blanklines >= 0) + putc('\n', output); + n_real_blanklines = 0; + if (parser_state_tos->ind_level == 0) + parser_state_tos->ind_stmt = 0; /* this is a class A kludge. dont do + * additional statement indentation if we are + * at bracket level 0 */ + + if (e_lab != s_lab || e_code != s_code) + ++code_lines; /* keep count of lines with code */ + + + if (e_lab != s_lab) { /* print lab, if any */ + if (comment_open) { + comment_open = 0; + fprintf(output, ".*/\n"); + } + while (e_lab > s_lab && (e_lab[-1] == ' ' || e_lab[-1] == '\t')) + e_lab--; + cur_col = pad_output(1, compute_label_target()); + fprintf(output, "%.*s", e_lab - s_lab, s_lab); + cur_col = count_spaces(cur_col, s_lab); + } + else + cur_col = 1; /* there is no label section */ + + parser_state_tos->pcase = false; + + if (s_code != e_code) { /* print code section, if any */ + register char *p; + + if (comment_open) { + comment_open = 0; + fprintf(output, ".*/\n"); + } + target_col = compute_code_target(); + /* If a line ends in an lparen character, the following + line should not line up with the parenthesis, but + should be indented by the usual amount. */ + if (parser_state_tos->last_token == lparen) + { + parser_state_tos->paren_indents[parser_state_tos->p_l_follow-1] + += ind_size - 1; + } + { + register i; + + for (i = 0; i < parser_state_tos->p_l_follow; i++) + if (parser_state_tos->paren_indents[i] >= 0) + parser_state_tos->paren_indents[i] = -(parser_state_tos->paren_indents[i] + target_col); + } + cur_col = pad_output(cur_col, target_col); + for (p = s_code; p < e_code; p++) + if (*p == (char) 0200) + fprintf(output, "%d", target_col * 7); + else + putc(*p, output); + cur_col = count_spaces(cur_col, s_code); + } + if (s_com != e_com) + { + if (troff) { + int all_here = 0; + register char *p; + + if (e_com[-1] == '/' && e_com[-2] == '*') + e_com -= 2, all_here++; + while (e_com > s_com && e_com[-1] == ' ') + e_com--; + *e_com = 0; + p = s_com; + while (*p == ' ') + p++; + if (p[0] == '/' && p[1] == '*') + p += 2, all_here++; + else if (p[0] == '*') + p += p[1] == '/' ? 2 : 1; + while (*p == ' ') + p++; + if (*p == 0) + goto inhibit_newline; + if (comment_open < 2 && parser_state_tos->box_com) { + comment_open = 0; + fprintf(output, ".*/\n"); + } + if (comment_open == 0) { + if ('a' <= *p && *p <= 'z') + *p = *p + 'A' - 'a'; + if (e_com - p < 50 && all_here == 2) { + register char *follow = p; + fprintf(output, "\n.nr C! \\w\1"); + while (follow < e_com) { + switch (*follow) { + case '\n': + putc(' ', output); + case 1: + break; + case '\\': + putc('\\', output); + default: + putc(*follow, output); + } + follow++; + } + putc(1, output); + } + fprintf(output, "\n./* %dp %d %dp\n", + parser_state_tos->com_col * 7, + (s_code != e_code || s_lab != e_lab) - parser_state_tos->box_com, + target_col * 7); + } + comment_open = 1 + parser_state_tos->box_com; + while (*p) { + if (*p == BACKSLASH) + putc(BACKSLASH, output); + putc(*p++, output); + } + } + else { /* print comment, if any */ + register target = parser_state_tos->com_col; + register char *com_st = s_com; + + target += parser_state_tos->comment_delta; + while (*com_st == '\t') + com_st++, target += 8; /* ? */ + while (target <= 0) + if (*com_st == ' ') + target++, com_st++; + else if (*com_st == '\t') + target = ((target - 1) & ~7) + 9, com_st++; + else + target = 1; + if (cur_col > target) { /* if comment cant fit on this line, + * put it on next line */ + putc('\n', output); + cur_col = 1; + ++parser_state_tos->out_lines; + } + while (e_com > com_st && isspace(e_com[-1])) + e_com--; + cur_col = pad_output(cur_col, target); + if (!parser_state_tos->box_com) { + if (star_comment_cont && (com_st[1] != '*' || e_com <= com_st + 1)) + if (com_st[1] == ' ' && com_st[0] == ' ' && e_com > com_st + 1) + com_st[1] = '*'; + else + fwrite(" * ", com_st[0] == '\t' ? 2 : com_st[0] == '*' ? 1 : 3, 1, output); + } + fwrite(com_st, e_com - com_st, 1, output); + parser_state_tos->comment_delta = parser_state_tos->n_comment_delta; + cur_col = count_spaces(cur_col, com_st); + ++parser_state_tos->com_lines; /* count lines with comments */ + } + } + if (parser_state_tos->use_ff) + { + putc('\014', output); + parser_state_tos->use_ff = false; + } + else + putc('\n', output); +inhibit_newline: + ++parser_state_tos->out_lines; + if (parser_state_tos->just_saw_decl == 1 && blanklines_after_declarations) { + prefix_blankline_requested = 1; + parser_state_tos->just_saw_decl = 0; + } + else + prefix_blankline_requested = postfix_blankline_requested; + postfix_blankline_requested = 0; + } + parser_state_tos->decl_on_line = parser_state_tos->in_decl; /* if we are in the middle of a + * declaration, remember that fact for + * proper comment indentation */ + parser_state_tos->ind_stmt = parser_state_tos->in_stmt & ~parser_state_tos->in_decl; /* next line should be + * indented if we have not + * completed this stmt and if + * we are not in the middle of + * a declaration */ + parser_state_tos->dumped_decl_indent = 0; + *(e_lab = s_lab) = '\0'; /* reset buffers */ + *(e_code = s_code) = '\0'; + *(e_com = s_com) = '\0'; + parser_state_tos->ind_level = parser_state_tos->i_l_follow; + parser_state_tos->paren_level = parser_state_tos->p_l_follow; + paren_target = -parser_state_tos->paren_indents[parser_state_tos->paren_level - 1]; + not_first_line = 1; + return; +} + +/* Figure out where we should put the code in codebuf. + Return the column number in spaces. */ +int +compute_code_target() +{ + register target_col = parser_state_tos->ind_level + 1; + + if (parser_state_tos->paren_level) + if (!lineup_to_parens) + target_col += continuation_indent * parser_state_tos->paren_level; + else { + register w; + register t = paren_target; + + if ((w = count_spaces(t, s_code) - max_col) > 0 + && count_spaces(target_col, s_code) <= max_col) { + t -= w + 1; + if (t > target_col) + target_col = t; + } + else + target_col = t; + } + else if (parser_state_tos->ind_stmt) + target_col += continuation_indent; + return target_col; +} + +int +compute_label_target() +{ + return + parser_state_tos->pcase ? case_ind + 1 + : *s_lab == '#' ? 1 + : parser_state_tos->ind_level - label_offset + 1; +} + +/* Allocate space for FILENAME, read in the file, and set in_prog and + in_prog_pos to point to the buffer. If any errors occur, report an + error message and abort. */ +void +read_file(filename) + char *filename; +{ + /* File descriptor for the input file */ + int in_fd; + + /* File status for the input file */ + struct stat in_stat; + + /* buffer used for error messages */ + char *errbuf; + + errbuf = (char *)xmalloc (strlen (filename) + 80); + sprintf(errbuf,"indent: %s",filename); + + in_fd = open(filename,O_RDONLY,0777); + if (in_fd < 0) + { + perror(errbuf); + exit(1); + } + + if (fstat(in_fd,&in_stat) < 0) + { + perror(errbuf); + exit(1); + } + in_prog_size = in_stat.st_size; + in_prog = xmalloc(in_prog_size + 3); /* 3 for ' ','\n','\0' */ + + if (read(in_fd,in_prog,in_prog_size) < 0) + { + perror(errbuf); + exit(1); + } + + if (close(in_fd) < 0) + { + perror(errbuf); + exit(1); + } + + in_prog[in_prog_size] = ' '; + in_prog[in_prog_size+1] = '\n'; + in_prog[in_prog_size+2] = 0; + in_prog_pos = in_prog; + + free (errbuf); +} + +/* Like read_file but read from stdin. */ +void +read_stdin() +{ + unsigned int alloc_size = 10000; + char ch; + unsigned int pos; + unsigned i; + + in_prog_pos = in_prog = xmalloc(alloc_size); + in_prog_size = 0; + do + { + /* Copy up until 3 bytes before the end of the buffer, + (the 3 is for ' \n\0')... */ + for (; in_prog_size < alloc_size - 3; in_prog_size++) + { + ch = getc(stdin); + if (ch == EOF) + break; + in_prog[in_prog_size] = ch; + } + /* ...and if that's not enough allocate more. */ + if (ch != EOF) { + alloc_size *= 2; + in_prog = xrealloc(in_prog,alloc_size); + } + } + while (ch != EOF); + + in_prog[in_prog_size] = ' '; + in_prog[in_prog_size+1] = '\n'; + in_prog[in_prog_size+2] = 0; + in_prog_pos = in_prog; +} + +/* Advance buf_ptr so that it points to the next line of input. Skip + over indent errors (comments beginning with *INDENT**), ignoring + them. Process INDENT ON and INDENT OFF. (Note: the name of this + function is a historical artifact from before the time that indent + kept the whole source file in memory). */ + +fill_buffer() +{ + /* Point various places in the buffer. */ + char *p; + + /* Have we found INDENT ON or INDENT OFF ? */ + enum {None,Indent_on,Indent_off} com; + + if (bp_save != 0) + { /* there is a partly filled input buffer left */ + buf_ptr = bp_save; /* dont read anything, just switch buffers */ + buf_end = be_save; + bp_save = be_save = 0; + if (buf_ptr < buf_end) + return; /* only return if there is really something in + * this buffer */ + } + + fill_it: + + cur_line = in_prog_pos; + buf_ptr = in_prog_pos; + for (p = buf_ptr; *p && *p++ != '\n';) + ; + + buf_end = p; + if (!*p) + had_eof = true; + + p = buf_ptr; + in_prog_pos = buf_end; + + while (*p == ' ' || *p == '\t') + p++; + if (*p == '/' && p[1] == '*') + { + p += 2; + if (p[1] == 'I' && strncmp(p,"*INDENT**",9) == 0) + goto fill_it; + while (*p == ' ' || *p == '\t') + p++; + com = None; + if (p[0] == 'I' && p[1] == 'N' && p[2] == 'D' && p[3] == 'E' + && p[4] == 'N' && p[5] == 'T') { + p += 6; + while (*p == ' ' || *p == '\t') + p++; + if (*p == '*') + com = 1; + else if (*p == 'O') + if (*++p == 'N') + p++, com = Indent_on; + else if (*p == 'F' && *++p == 'F') + p++, com = Indent_off; + while (*p == ' ' || *p == '\t') + p++; + if (p[0] == '*' && p[1] == '/' && p[2] == '\n' && com) { + if (s_com != e_com || s_lab != e_lab || s_code != e_code) + dump_line(); + if (!(inhibit_formatting = com - 1)) { + n_real_blanklines = 0; + postfix_blankline_requested = 0; + prefix_blankline_requested = 0; + suppress_blanklines = 1; + } + } + } + } + if (inhibit_formatting) + { + p = buf_ptr; + do + putc(*p,output); + while (*p++ != '\n'); + } + +} + + + +/* + * Copyright (C) 1976 by the Board of Trustees of the University of Illinois + * + * All rights reserved + * + * + * NAME: pad_output + * + * FUNCTION: Writes tabs and spaces to move the current column up to the desired + * position. + * + * ALGORITHM: Put tabs and/or blanks into pobuf, then write pobuf. + * + * PARAMETERS: current integer The current column target + * nteger The desired column + * + * RETURNS: Integer value of the new column. (If current >= target, no action is + * taken, and current is returned. + * + * GLOBALS: None + * + * CALLS: write (sys) + * + * CALLED BY: dump_line + * + * HISTORY: initial coding November 1976 D A Willcox of CAC + * + */ +pad_output(current, target) /* writes tabs and blanks (if necessary) to + * get the current output position up to the + * target column */ + int current; /* the current column value */ + int target; /* position we want it at */ +{ + register int curr; /* internal column pointer */ + register int tcur; + + if (troff) + fprintf(output, "\\h'|%dp'", (target - 1) * 7); + else { + if (current >= target) + return (current); /* line is already long enough */ + curr = current; + while ((tcur = ((curr - 1) & tabmask) + tabsize + 1) <= target) { + putc('\t', output); + curr = tcur; + } + while (curr++ < target) + putc(' ', output); /* pad with final blanks */ + } + return (target); +} + +/* + * Copyright (C) 1976 by the Board of Trustees of the University of Illinois + * + * All rights reserved + * + * + * NAME: count_spaces + * + * FUNCTION: Find out where printing of a given string will leave the current + * character position on output. + * + * ALGORITHM: Run thru input string and add appropriate values to current + * position. + * + * RETURNS: Integer value of position after printing "buffer" starting in column + * "current". + * + * HISTORY: initial coding November 1976 D A Willcox of CAC + * + */ +int +count_spaces(current, buffer) +/* + * this routine figures out where the character position will be after + * printing the text in buffer starting at column "current" + */ + int current; + char *buffer; +{ + register char *buf; /* used to look thru buffer */ + register int cur; /* current character counter */ + + cur = current; + + for (buf = buffer; *buf != '\0'; ++buf) { + switch (*buf) { + + case '\n': + case 014: /* form feed */ + cur = 1; + break; + + case '\t': + cur = ((cur - 1) & tabmask) + tabsize + 1; + break; + + case '': /* this is a backspace */ + --cur; + break; + + default: + ++cur; + break; + } /* end of switch */ + } /* end of for loop */ + return (cur); +} + +/* Nonzero if we have found an error (not a warning). */ +int found_err; + +/* Signal an error. LEVEL is nonzero if it is an error (as opposed to + a warning. MSG is a printf-style format string. Additional + arguments are additional arguments for printf. */ +diag(level, msg, a, b) +{ + if (level) + found_err = 1; + if (output == stdout) { + fprintf(stdout, "/**INDENT** %s@%d: ", level == 0 ? "Warning" : "Error", line_no); + fprintf(stdout, (char *)msg, a, b); + fprintf(stdout, " */\n"); + } + else { + fprintf(stderr, "%s: %d: ", in_name, line_no); + fprintf(stderr, (char *)msg, a, b); + fprintf(stderr, "\n"); + } +} + +writefdef(f, nm) + register struct fstate *f; +{ + fprintf(output, ".ds f%c %s\n.nr s%c %d\n", + nm, f->font, nm, f->size); +} + +/* Write characters starting at S to change the font from OF to NF. Return + a pointer to the character after the last character written. + For troff mode only. */ +char * +chfont(of, nf, s) + register struct fstate *of, + *nf; + char *s; +{ + if (of->font[0] != nf->font[0] + || of->font[1] != nf->font[1]) { + *s++ = '\\'; + *s++ = 'f'; + if (nf->font[1]) { + *s++ = '('; + *s++ = nf->font[0]; + *s++ = nf->font[1]; + } + else + *s++ = nf->font[0]; + } + if (nf->size != of->size) { + *s++ = '\\'; + *s++ = 's'; + if (nf->size < of->size) { + *s++ = '-'; + *s++ = '0' + of->size - nf->size; + } + else { + *s++ = '+'; + *s++ = '0' + nf->size - of->size; + } + } + return s; +} + + +parsefont(f, s0) + register struct fstate *f; + char *s0; +{ + register char *s = s0; + int sizedelta = 0; + int i; + + f->size = 0; + f->allcaps = 1; + for (i = 0; i < 4; i++) + f->font[i] = 0; + + while (*s) { + if (isdigit(*s)) + f->size = f->size * 10 + *s - '0'; + else if (isupper(*s)) + if (f->font[0]) + f->font[1] = *s; + else + f->font[0] = *s; + else if (*s == 'c') + f->allcaps = 1; + else if (*s == '+') + sizedelta++; + else if (*s == '-') + sizedelta--; + else { + fprintf(stderr, "indent: bad font specification: %s\n", s0); + exit(1); + } + s++; + } + if (f->font[0] == 0) + f->font[0] = 'R'; + if (bodyf.size == 0) + bodyf.size = 11; + if (f->size == 0) + f->size = bodyf.size + sizedelta; + else if (sizedelta > 0) + f->size += bodyf.size; + else + f->size = bodyf.size - f->size; +} diff --git a/src/util/indent/lexi.c b/src/util/indent/lexi.c new file mode 100644 index 0000000..b0d5113 --- /dev/null +++ b/src/util/indent/lexi.c @@ -0,0 +1,584 @@ +/* + * Copyright (c) 1985 Sun Microsystems, Inc. + * Copyright (c) 1980 The Regents of the University of California. + * Copyright (c) 1976 Board of Trustees of the University of Illinois. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley, the University of Illinois, + * Urbana, and Sun Microsystems, Inc. The name of either University + * or Sun Microsystems may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifndef lint +static char sccsid[] = "@(#)lexi.c 5.11 (Berkeley) 9/15/88"; +#endif /* not lint */ + +/* + * Here we have the token scanner for indent. It scans off one token and puts + * it in the global variable "token". It returns a code, indicating the type + * of token scanned. + */ + +#include "indent_globs.h" +#include "ctype.h" + +#define alphanum 1 +#define opchar 3 + +enum rwcodes { + rw_break, + rw_switch, + rw_case, + rw_struct_like, /* struct, enum, union */ + rw_decl, + rw_sp_paren, /* if, while, for */ + rw_sp_nparen, /* do, else */ + rw_sizeof + }; + +struct templ { + char *rwd; + enum rwcodes rwcode; +}; + +struct templ *user_specials = 0; +unsigned int user_specials_max, user_specials_idx; +struct templ specials[] = +{ + {"switch", rw_switch}, + {"case", rw_case}, + {"break", rw_break}, + {"struct", rw_struct_like}, + {"union", rw_struct_like}, + {"enum", rw_struct_like}, + {"default", rw_case}, + {"int", rw_decl}, + {"char", rw_decl}, + {"float", rw_decl}, + {"double", rw_decl}, +/* {"long", rw_decl}, + {"short", rw_decl},*/ + {"typdef", rw_decl}, + {"unsigned", rw_decl}, + {"register", rw_decl}, + {"static", rw_decl}, + {"global", rw_decl}, + {"extern", rw_decl}, + {"void", rw_decl}, + {"va_dcl", rw_decl}, + {"goto", rw_break}, + {"return", rw_break}, + {"if", rw_sp_paren}, + {"while", rw_sp_paren}, + {"for", rw_sp_paren}, + {"else", rw_sp_nparen}, + {"do", rw_sp_nparen}, + {"sizeof", rw_sizeof}, + {0, 0} +}; + +char chartype[128] = +{ /* this is used to facilitate the decision of + * what type (alphanumeric, operator) each + * character is */ + 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, 3, 0, 0, 1, 3, 3, 0, + 0, 0, 3, 3, 0, 3, 0, 3, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 0, 0, 3, 3, 3, 3, + 0, 1, 1, 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, 0, 0, 3, 1, + 0, 1, 1, 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, 3, 0, 3, 0 +}; + + + + +enum codes +lexi() +{ + /* used to walk through the token */ + char *tok; + + int unary_delim; /* this is set to 1 if the current token + * + * forces a following operator to be unary */ + static enum codes last_code; /* the last token type returned */ + static int l_struct; /* set to 1 if the last token was 'struct' */ + int code; /* internal code to be returned */ + char qchar; /* the delimiter character for a string */ + + unary_delim = false; + parser_state_tos->col_1 = parser_state_tos->last_nl; /* tell world that this token started in + * column 1 iff the last thing scanned was nl */ + parser_state_tos->last_nl = false; + + while (*buf_ptr == ' ' || *buf_ptr == '\t') { /* get rid of blanks */ + parser_state_tos->col_1 = false; /* leading blanks imply token is not in column + * 1 */ + if (++buf_ptr >= buf_end) + fill_buffer(); + } + + token = buf_ptr; + + /* Scan an alphanumeric token */ + if (chartype[*buf_ptr] == alphanum || buf_ptr[0] == '.' && isdigit(buf_ptr[1])) { + /* + * we have a character or number + */ + register char *j; /* used for searching thru list of + * + * reserved words */ + register struct templ *p; + + if (isdigit(*buf_ptr) || buf_ptr[0] == '.' && isdigit(buf_ptr[1])) { + int seendot = 0, + seenexp = 0; + if (*buf_ptr == '0' && + (buf_ptr[1] == 'x' || buf_ptr[1] == 'X')) { + buf_ptr += 2; + while (isxdigit(*buf_ptr)) + buf_ptr++; + } + else + while (1) { + if (*buf_ptr == '.') + if (seendot) + break; + else + seendot++; + buf_ptr++; + if (!isdigit(*buf_ptr) && *buf_ptr != '.') + if ((*buf_ptr != 'E' && *buf_ptr != 'e') || seenexp) + break; + else { + seenexp++; + seendot++; + buf_ptr++; + if (*buf_ptr == '+' || *buf_ptr == '-') + buf_ptr++; + } + } + if (*buf_ptr == 'L' || *buf_ptr == 'l') + buf_ptr++; + } + else + while (chartype[*buf_ptr] == alphanum) { /* copy it over */ + buf_ptr++; + if (buf_ptr >= buf_end) + fill_buffer(); + } + token_end = buf_ptr; + while (*buf_ptr == ' ' || *buf_ptr == '\t') { /* get rid of blanks */ + if (++buf_ptr >= buf_end) + fill_buffer(); + } + parser_state_tos->its_a_keyword = false; + parser_state_tos->sizeof_keyword = false; + if (l_struct) { /* if last token was 'struct', then this token + * should be treated as a declaration */ + l_struct = false; + last_code = ident; + parser_state_tos->last_u_d = true; + return (decl); + } + parser_state_tos->last_u_d = false; /* Operator after indentifier is binary */ + last_code = ident; /* Remember that this is the code we will + * return */ + + /* + * This loop will check if the token is a keyword. + */ + for (p = specials; (j = p->rwd) != 0; p++) { + tok = token; /* point at scanned token */ + if (*j++ != *tok++ || *j++ != *tok++) + continue; /* This test depends on the fact that + * identifiers are always at least 1 character + * long (ie. the first two bytes of the + * identifier are always meaningful) */ + if (tok >= token_end) + break; /* If its a 1 or 2 character identifier */ + while (tok < token_end && *tok++ == *j++) + if (*j == 0 && tok == token_end) + goto found_keyword; /* I wish that C had a multi-level + * break... */ + } + if (p->rwd) { /* we have a keyword */ + found_keyword: + parser_state_tos->its_a_keyword = true; + parser_state_tos->last_u_d = true; + switch (p->rwcode) { + case rw_switch: /* it is a switch */ + return (swstmt); + case rw_case: /* a case or default */ + return (casestmt); + + case rw_struct_like: /* a "struct" */ + if (parser_state_tos->p_l_follow) + break; /* inside parens: cast */ + l_struct = true; + + /* + * Next time around, we will want to know that we have had a + * 'struct' + */ + case rw_decl: /* one of the declaration keywords */ + if (parser_state_tos->p_l_follow) { + parser_state_tos->cast_mask |= 1 << parser_state_tos->p_l_follow; + break; /* inside parens: cast */ + } + last_code = decl; + return (decl); + + case rw_sp_paren: /* if, while, for */ + return (sp_paren); + + case rw_sp_nparen: /* do, else */ + return (sp_nparen); + + case rw_sizeof: + parser_state_tos->sizeof_keyword = true; + default: /* all others are treated like any other + * identifier */ + return (ident); + } /* end of switch */ + } /* end of if (found_it) */ + if (*buf_ptr == '(' && parser_state_tos->tos <= 1 && parser_state_tos->ind_level == 0) { + register char *tp = buf_ptr; + while (tp < buf_end) + if (*tp++ == ')' && *tp == ';') + goto not_proc; + parser_state_tos->procname = token; + parser_state_tos->procname_end = token_end; + parser_state_tos->in_parameter_declaration = 1; + not_proc:; + } + /* + * The following hack attempts to guess whether or not the current + * token is in fact a declaration keyword -- one that has been + * typedefd + */ + if (((*buf_ptr == '*' && buf_ptr[1] != '=') || isalpha(*buf_ptr) || *buf_ptr == '_') + && !parser_state_tos->p_l_follow + && !parser_state_tos->block_init + && (parser_state_tos->last_token == rparen || parser_state_tos->last_token == semicolon || + parser_state_tos->last_token == decl || + parser_state_tos->last_token == lbrace || parser_state_tos->last_token == rbrace)) { + parser_state_tos->its_a_keyword = true; + parser_state_tos->last_u_d = true; + last_code = decl; + return decl; + } + if (last_code == decl) /* if this is a declared variable, then + * following sign is unary */ + parser_state_tos->last_u_d = true; /* will make "int a -1" work */ + last_code = ident; + return (ident); /* the ident is not in the list */ + } /* end of procesing for alpanum character */ + /* l l l Scan a non-alphanumeric token */ + + /* If it is not a one character token, token_end will get changed + later. */ + token_end = buf_ptr + 1; + + if (++buf_ptr >= buf_end) + fill_buffer(); + + switch (*token) { + case '\n': + unary_delim = parser_state_tos->last_u_d; + parser_state_tos->last_nl = true; /* remember that we just had a newline */ + code = (had_eof ? 0 : newline); + + /* + * if data has been exausted, the newline is a dummy, and we should + * return code to stop + */ + break; + + case '\'': /* start of quoted character */ + case '"': /* start of string */ + qchar = *token; + + /* Find out how big the literal is so we can set token_end. */ + + /* Invariant: before loop test buf_ptr points to the next */ + /* character that we have not yet checked. */ + while (*buf_ptr != qchar && *buf_ptr != 0 && *buf_ptr != '\n') + { + if (*buf_ptr == '\\') + { + buf_ptr++; + if (buf_ptr >= buf_end) + fill_buffer (); + if (*buf_ptr == '\n') + ++line_no; + if (*buf_ptr == 0) + break; + } + buf_ptr++; + if (buf_ptr >= buf_end) + fill_buffer (); + } + if (*buf_ptr == '\n' || *buf_ptr == 0) + { + diag (1, + qchar == '\'' + ? "Unterminated character constant" + : "Unterminated string constant" + ); + } + else + { + /* Advance over end quote char. */ + buf_ptr++; + if (buf_ptr >= buf_end) + fill_buffer (); + } + + code = ident; + break; + + case ('('): + if (lpc && *buf_ptr == '{') { + buf_ptr++; + } + case ('['): + unary_delim = true; + code = lparen; + break; + + case (')'): + case (']'): + code = rparen; + break; + + case '#': + unary_delim = parser_state_tos->last_u_d; + code = preesc; + break; + + case '?': + unary_delim = true; + code = question; + break; + + case (':'): + if (lpc && *buf_ptr == ':') { + buf_ptr++; + code = unary_op; + unary_delim = true; + break; + } + code = colon; + unary_delim = true; + break; + + case (';'): + unary_delim = true; + code = semicolon; + break; + + case ('{'): + unary_delim = true; + + /* This check is made in the code for '='. No one who writes + initializers without '=' these days deserves to have indent + work on their code (besides which, uncommenting this would + screw up anything which assumes that parser_state_tos->block_init really + means you are in an initializer. */ + /* + * if (parser_state_tos->in_or_st) parser_state_tos->block_init = 1; + */ + + /* The following neat hack causes the braces in structure + initializations to be treated as parentheses, thus causing + initializations to line up correctly, e.g. + struct foo bar = + {{a, + b, + c}, + {1, + 2}}; + If lparen is returned, token can be used to distinguish + between '{' and '(' where necessary. */ + + code = parser_state_tos->block_init ? lparen : lbrace; + break; + + case ('}'): + if (lpc && *buf_ptr == ')') { + buf_ptr++; + code = rparen; + break; + } + unary_delim = true; + /* The following neat hack is explained under '{' above. */ + code = parser_state_tos->block_init ? rparen : rbrace; + + break; + + case 014: /* a form feed */ + unary_delim = parser_state_tos->last_u_d; + parser_state_tos->last_nl = true; /* remember this so we can set 'parser_state_tos->col_1' + * right */ + code = form_feed; + break; + + case (','): + unary_delim = true; + code = comma; + break; + + case '.': + unary_delim = false; + code = period; + break; + + case '-': + case '+': /* check for -, +, --, ++ */ + code = (parser_state_tos->last_u_d ? unary_op : binary_op); + unary_delim = true; + + if (*buf_ptr == token[0]) { + /* check for doubled character */ + buf_ptr++; + /* buffer overflow will be checked at end of loop */ + if (last_code == ident || last_code == rparen) { + code = (parser_state_tos->last_u_d ? unary_op : postop); + /* check for following ++ or -- */ + unary_delim = false; + } + } + else if (*buf_ptr == '=') + /* check for operator += */ + buf_ptr++; + else if (*buf_ptr == '>') { + /* check for operator -> */ + buf_ptr++; + if (!pointer_as_binop) { + unary_delim = false; + code = unary_op; + parser_state_tos->want_blank = false; + } + } + break; /* buffer overflow will be checked at end of + * switch */ + + case '=': + if (parser_state_tos->in_or_st) + parser_state_tos->block_init = 1; + + if (*buf_ptr == '=') /* == */ + buf_ptr++; + + code = binary_op; + unary_delim = true; + break; + /* can drop thru!!! */ + + case '>': + case '<': + case '!': /* ops like <, <<, <=, !=, etc */ + if (*buf_ptr == '>' || *buf_ptr == '<' || *buf_ptr == '=') { + if (++buf_ptr >= buf_end) + fill_buffer(); + } + + code = (parser_state_tos->last_u_d ? unary_op : binary_op); + unary_delim = true; + break; + + default: + if (token[0] == '/' && *buf_ptr == '*') { + /* it is start of comment */ + + if (++buf_ptr >= buf_end) + fill_buffer(); + + code = comment; + unary_delim = parser_state_tos->last_u_d; + break; + } + while (*(buf_ptr - 1) == *buf_ptr || *buf_ptr == '=') { + /* + * handle ||, &&, etc, and also things as in int *****i + */ + if (++buf_ptr >= buf_end) + fill_buffer(); + } + code = (parser_state_tos->last_u_d ? unary_op : binary_op); + unary_delim = true; + + + } /* end of switch */ + if (code != newline) { + l_struct = false; + last_code = code; + } + token_end = buf_ptr; + if (buf_ptr >= buf_end) /* check for input buffer empty */ + fill_buffer(); + parser_state_tos->last_u_d = unary_delim; + + return (code); +} + +/* + * Add the given keyword to the keyword table, using val as the keyword type + */ +addkey(key, val) + char *key; + enum rwcodes val; +{ + register struct templ *p = specials; + while (p->rwd) + if (p->rwd[0] == key[0] && strcmp(p->rwd, key) == 0) + return; + else + p++; + + if (user_specials == 0) + { + user_specials = (struct templ *) xmalloc (5 * sizeof (struct templ)); + if (user_specials == 0) + { + fputs ("indent: out of memory\n", stderr); + exit (1); + } + user_specials_max = 5; + user_specials_idx = 0; + } + else if (user_specials_idx == user_specials_max) + { + user_specials_max += 5; + user_specials = (struct templ *) xrealloc ((char *) user_specials, + user_specials_max + * sizeof (struct templ)); + } + p = &user_specials[user_specials_idx++]; + + p->rwd = key; + p->rwcode = val; + p[1].rwd = 0; + p[1].rwcode = 0; + return; +} diff --git a/src/util/indent/parse.c b/src/util/indent/parse.c new file mode 100644 index 0000000..7ebd60c --- /dev/null +++ b/src/util/indent/parse.c @@ -0,0 +1,359 @@ +/* + * Copyright (c) 1985 Sun Microsystems, Inc. + * Copyright (c) 1980 The Regents of the University of California. + * Copyright (c) 1976 Board of Trustees of the University of Illinois. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley, the University of Illinois, + * Urbana, and Sun Microsystems, Inc. The name of either University + * or Sun Microsystems may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifndef lint +static char sccsid[] = "@(#)parse.c 5.8 (Berkeley) 9/15/88"; +#endif /* not lint */ + +#include "indent_globs.h" + +struct parser_state *parser_state_tos; + +/* like ++parser_state_tos->tos but checks for stack overflow and extends + stack if necessary. */ +static int +inc_pstack () +{ + if (++parser_state_tos->tos >= parser_state_tos->p_stack_size) + { + parser_state_tos->p_stack_size *= 2; + parser_state_tos->p_stack = (enum codes *) + xrealloc (parser_state_tos->p_stack, + parser_state_tos->p_stack_size * sizeof (enum codes)); + parser_state_tos->il = (int *) + xrealloc (parser_state_tos->il, + parser_state_tos->p_stack_size * sizeof (int)); + parser_state_tos->cstk = (int *) + xrealloc (parser_state_tos->cstk, + parser_state_tos->p_stack_size * sizeof (int)); + } + return parser_state_tos->tos; +} + +void +parse(tk) + enum codes tk; /* the code for the construct scanned */ +{ + int i; + +#ifdef debug + printf("%2d - %s\n", tk, token); +#endif + + while (parser_state_tos->p_stack[parser_state_tos->tos] == ifhead && tk != elselit) { + /* true if we have an if without an else */ + parser_state_tos->p_stack[parser_state_tos->tos] = stmt; /* apply the if(..) stmt ::= stmt + * reduction */ + reduce(); /* see if this allows any reduction */ + } + + + switch (tk) { /* go on and figure out what to do with the + * input */ + + case decl: /* scanned a declaration word */ + parser_state_tos->search_brace = btype_2; + /* indicate that following brace should be on same line */ + if (parser_state_tos->p_stack[parser_state_tos->tos] != decl) { /* only put one declaration + * onto stack */ + break_comma = true; /* while in declaration, newline should be + * forced after comma */ + parser_state_tos->p_stack[inc_pstack()] = decl; + parser_state_tos->il[parser_state_tos->tos] = parser_state_tos->i_l_follow; + + if (ljust_decl) {/* only do if we want left justified + * declarations */ + parser_state_tos->ind_level = 0; + for (i = parser_state_tos->tos - 1; i > 0; --i) + if (parser_state_tos->p_stack[i] == decl) + /* indentation is number of declaration levels deep + we are times spaces per level */ + parser_state_tos->ind_level += ind_size; + parser_state_tos->i_l_follow = parser_state_tos->ind_level; + } + } + break; + + case ifstmt: /* scanned if (...) */ + if (parser_state_tos->p_stack[parser_state_tos->tos] == elsehead + && else_if) /* "else if ..." */ + parser_state_tos->i_l_follow = parser_state_tos->il[parser_state_tos->tos]; + case dolit: /* 'do' */ + case forstmt: /* for (...) */ + inc_pstack(); + parser_state_tos->p_stack[parser_state_tos->tos] = tk; + parser_state_tos->il[parser_state_tos->tos] = parser_state_tos->ind_level = parser_state_tos->i_l_follow; + parser_state_tos->i_l_follow += ind_size; /* subsequent statements should be indented 1 */ + parser_state_tos->search_brace = btype_2; + break; + + case lbrace: /* scanned { */ + break_comma = false; /* don't break comma in an initial list */ + if (parser_state_tos->p_stack[parser_state_tos->tos] == stmt || parser_state_tos->p_stack[parser_state_tos->tos] == decl + || parser_state_tos->p_stack[parser_state_tos->tos] == stmtl) + /* it is a random, isolated stmt group or a declaration */ + parser_state_tos->i_l_follow += ind_size; + else { + if (s_code == e_code) { + /* + * only do this if there is nothing on the line + */ + + parser_state_tos->ind_level -= ind_size; + /* + * it is a group as part of a while, for, etc. + */ + + /* For -bl formatting, indent by brace_indent + additional spaces + e.g. + if (foo == bar) + { + <--> brace_indent spaces (in this example, 4) + */ + if (!btype_2) + { + parser_state_tos->ind_level += brace_indent; + parser_state_tos->i_l_follow += brace_indent; + if (parser_state_tos->p_stack[parser_state_tos->tos] == swstmt) + case_ind += brace_indent; + } + + if (parser_state_tos->p_stack[parser_state_tos->tos] == swstmt + && case_indent + >= ind_size) + parser_state_tos->ind_level -= ind_size; + /* + * for a switch, brace should be two levels out from the code + */ + } + } + + inc_pstack(); + parser_state_tos->p_stack[parser_state_tos->tos] = lbrace; + parser_state_tos->il[parser_state_tos->tos] = parser_state_tos->ind_level; + inc_pstack(); + parser_state_tos->p_stack[parser_state_tos->tos] = stmt; + /* allow null stmt between braces */ + parser_state_tos->il[parser_state_tos->tos] = parser_state_tos->i_l_follow; + break; + + case whilestmt: /* scanned while (...) */ + if (parser_state_tos->p_stack[parser_state_tos->tos] == dohead) { + /* it is matched with do stmt */ + parser_state_tos->ind_level = parser_state_tos->i_l_follow = parser_state_tos->il[parser_state_tos->tos]; + inc_pstack(); + parser_state_tos->p_stack[parser_state_tos->tos] = whilestmt; + parser_state_tos->il[parser_state_tos->tos] = parser_state_tos->ind_level = parser_state_tos->i_l_follow; + } + else { /* it is a while loop */ + inc_pstack(); + parser_state_tos->p_stack[parser_state_tos->tos] = whilestmt; + parser_state_tos->il[parser_state_tos->tos] = parser_state_tos->i_l_follow; + parser_state_tos->i_l_follow += ind_size; + parser_state_tos->search_brace = btype_2; + } + + break; + + case elselit: /* scanned an else */ + + if (parser_state_tos->p_stack[parser_state_tos->tos] != ifhead) + diag(1, "Unmatched 'else'"); + else { + parser_state_tos->ind_level = parser_state_tos->il[parser_state_tos->tos]; /* indentation for else should + * be same as for if */ + /* everything following should be in 1 level */ + parser_state_tos->i_l_follow = parser_state_tos->ind_level + ind_size; + + parser_state_tos->p_stack[parser_state_tos->tos] = elsehead; + /* remember if with else */ + parser_state_tos->search_brace = btype_2 | else_if; + } + break; + + case rbrace: /* scanned a } */ + /* stack should have or */ + if (parser_state_tos->p_stack[parser_state_tos->tos - 1] == lbrace) { + parser_state_tos->ind_level = parser_state_tos->i_l_follow = parser_state_tos->il[--parser_state_tos->tos]; + parser_state_tos->p_stack[parser_state_tos->tos] = stmt; + } + else + diag(1, "Stmt nesting error."); + break; + + case swstmt: /* had switch (...) */ + inc_pstack(); + parser_state_tos->p_stack[parser_state_tos->tos] = swstmt; + parser_state_tos->cstk[parser_state_tos->tos] = case_ind; + /* save current case indent level */ + parser_state_tos->il[parser_state_tos->tos] = parser_state_tos->i_l_follow; + case_ind = parser_state_tos->i_l_follow + case_indent; /* cases should be one + * level down from + * switch */ + /* statements should be two levels in */ + parser_state_tos->i_l_follow += case_indent + ind_size; + + parser_state_tos->search_brace = btype_2; + break; + + case semicolon: /* this indicates a simple stmt */ + break_comma = false; /* turn off flag to break after commas in a + * declaration */ + inc_pstack(); + parser_state_tos->p_stack[parser_state_tos->tos] = stmt; + parser_state_tos->il[parser_state_tos->tos] = parser_state_tos->ind_level; + break; + + default: /* this is an error */ + diag(1, "Unknown code to parser"); + return; + + + } /* end of switch */ + + reduce(); /* see if any reduction can be done */ + +#ifdef debug + for (i = 1; i <= parser_state_tos->tos; ++i) + printf("(%d %d)", parser_state_tos->p_stack[i], parser_state_tos->il[i]); + printf("\n"); +#endif + + return; +} + +/* + * Copyright (C) 1976 by the Board of Trustees of the University of Illinois + * + * All rights reserved + * + * + * NAME: reduce + * + * FUNCTION: Implements the reduce part of the parsing algorithm + * + * ALGORITHM: The following reductions are done. Reductions are repeated until + * no more are possible. + * + * Old TOS New TOS do + * "dostmt" if "ifstmt" switch decl + * "ifelse" for while + * "dostmt" while + * + * On each reduction, parser_state_tos->i_l_follow (the indentation for the following line) is + * set to the indentation level associated with the old TOS. + * + * PARAMETERS: None + * + * RETURNS: Nothing + * + * GLOBALS: parser_state_tos->cstk parser_state_tos->i_l_follow = parser_state_tos->il parser_state_tos->p_stack = parser_state_tos->tos = + * + * CALLS: None + * + * CALLED BY: parse  + * + * HISTORY: initial coding November 1976 D A Willcox of CAC + * + */ +/*----------------------------------------------*\ +| REDUCTION PHASE | +\*----------------------------------------------*/ +reduce() +{ + + register int i; + + for (;;) { /* keep looping until there is nothing left to + * reduce */ + + switch (parser_state_tos->p_stack[parser_state_tos->tos]) { + + case stmt: + switch (parser_state_tos->p_stack[parser_state_tos->tos - 1]) { + + case stmt: + case stmtl: + /* stmtl stmt or stmt stmt */ + parser_state_tos->p_stack[--parser_state_tos->tos] = stmtl; + break; + + case dolit: /* */ + parser_state_tos->p_stack[--parser_state_tos->tos] = dohead; + parser_state_tos->i_l_follow = parser_state_tos->il[parser_state_tos->tos]; + break; + + case ifstmt: + /* */ + parser_state_tos->p_stack[--parser_state_tos->tos] = ifhead; + for (i = parser_state_tos->tos - 1; + ( + parser_state_tos->p_stack[i] != stmt + && + parser_state_tos->p_stack[i] != stmtl + && + parser_state_tos->p_stack[i] != lbrace + ); + --i); + parser_state_tos->i_l_follow = parser_state_tos->il[i]; + /* + * for the time being, we will assume that there is no else on + * this if, and set the indentation level accordingly. If an + * else is scanned, it will be fixed up later + */ + break; + + case swstmt: + /* */ + case_ind = parser_state_tos->cstk[parser_state_tos->tos - 1]; + + case decl: /* finish of a declaration */ + case elsehead: + /* < else> */ + case forstmt: + /* */ + case whilestmt: + /* */ + parser_state_tos->p_stack[--parser_state_tos->tos] = stmt; + parser_state_tos->i_l_follow = parser_state_tos->il[parser_state_tos->tos]; + break; + + default: /* */ + return; + + } /* end of section for on top of stack */ + break; + + case whilestmt: /* while (...) on top */ + if (parser_state_tos->p_stack[parser_state_tos->tos - 1] == dohead) { + /* it is termination of a do while */ + parser_state_tos->p_stack[--parser_state_tos->tos] = stmt; + break; + } + else + return; + + default: /* anything else on top */ + return; + + } + } +} diff --git a/src/util/indent/pr_comment.c b/src/util/indent/pr_comment.c new file mode 100644 index 0000000..fd2e5af --- /dev/null +++ b/src/util/indent/pr_comment.c @@ -0,0 +1,415 @@ +/* + * Copyright (c) 1985 Sun Microsystems, Inc. + * Copyright (c) 1980 The Regents of the University of California. + * Copyright (c) 1976 Board of Trustees of the University of Illinois. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley, the University of Illinois, + * Urbana, and Sun Microsystems, Inc. The name of either University + * or Sun Microsystems may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifndef lint +static char sccsid[] = "@(#)pr_comment.c 5.9 (Berkeley) 9/15/88"; +#endif /* not lint */ + +/* + * NAME: + * pr_comment + * + * FUNCTION: + * This routine takes care of scanning and printing comments. + * + * ALGORITHM: + * 1) Decide where the comment should be aligned, and if lines should + * be broken. + * 2) If lines should not be broken and filled, just copy up to end of + * comment. + * 3) If lines should be filled, then scan thru input_buffer copying + * characters to com_buf. Remember where the last blank, tab, or + * newline was. When line is filled, print up to last blank and + * continue copying. + * + * HISTORY: + * November 1976 D A Willcox of CAC Initial coding + * 12/6/76 D A Willcox of CAC Modification to handle + * UNIX-style comments + * + */ + +/* + * this routine processes comments. It makes an attempt to keep comments from + * going over the max line length. If a line is too long, it moves everything + * from the last blank to the next comment line. Blanks and tabs from the + * beginning of the input line are removed + */ + + +#include "indent_globs.h" + + +pr_comment() +{ + int now_col; /* column we are in now */ + int adj_max_col; /* Adjusted max_col for when we decide to + * spill comments over the right margin */ + char *last_bl; /* points to the last blank in the output + * buffer */ + char *t_ptr; /* used for moving string */ + int unix_comment; /* tri-state variable used to decide if it is + * a unix-style comment. 0 means only blanks + * since '/ *', 1 means regular style comment, 2 + * means unix style comment */ + int break_delim = comment_delimiter_on_blankline; + int l_just_saw_decl = parser_state_tos->just_saw_decl; +#if 0 + int parser_state_tos->last_nl = 0; /* true iff the last significant thing + * weve seen is a newline + */ +#endif + int one_liner = 1; /* true iff this comment is a one-liner */ + adj_max_col = max_col; + parser_state_tos->just_saw_decl = 0; + last_bl = 0; /* no blanks found so far */ + parser_state_tos->box_com = false; /* at first, assume that we are not in + * a boxed comment or some other + * comment that should not be touched */ + ++parser_state_tos->out_coms; /* keep track of number of comments */ + unix_comment = 1; /* set flag to let us figure out if there is a + * unix-style comment ** DISABLED: use 0 to + * reenable this hack! */ + + /* Figure where to align and how to treat the comment */ + + if (parser_state_tos->col_1 && !format_col1_comments) { /* if comment starts in column + * 1 it should not be touched */ + parser_state_tos->box_com = true; + parser_state_tos->com_col = 1; + } + else { + if (*buf_ptr == '-' || *buf_ptr == '*' || !format_comments) { + parser_state_tos->box_com = true; /* a comment with a '-' or '*' immediately + * after the '/ *' is assumed to be a boxed + * comment */ + break_delim = 0; + } + if ( /* parser_state_tos->bl_line && */ (s_lab == e_lab) && (s_code == e_code)) { + /* klg: check only if this line is blank */ + /* + * If this (*and previous lines are*) blank, dont put comment way + * out at left + */ + parser_state_tos->com_col = (parser_state_tos->ind_level - unindent_displace) + 1; + adj_max_col = block_comment_max_col; + if (parser_state_tos->com_col <= 1) + parser_state_tos->com_col = 1 + !format_col1_comments; + } + else { + register target_col; + break_delim = 0; + if (s_code != e_code) + target_col = count_spaces(compute_code_target(), s_code); + else { + target_col = 1; + if (s_lab != e_lab) + target_col = count_spaces(compute_label_target(), s_lab); + } + parser_state_tos->com_col = parser_state_tos->decl_on_line || parser_state_tos->ind_level == 0 ? decl_com_ind : com_ind; + /* If we are already past the position for the comment, + put it at the next tab stop. */ + if (parser_state_tos->com_col < target_col) + parser_state_tos->com_col = ((target_col + 7) & ~7) + 1; + if (else_or_endif) + { + parser_state_tos->com_col = else_endif_col; + else_or_endif = false; + /* We want the comment to appear one space after the #else + or #endif. */ + if (parser_state_tos->com_col < target_col) + parser_state_tos->com_col = target_col + 1; + } + if (parser_state_tos->com_col + 24 > adj_max_col) + adj_max_col = parser_state_tos->com_col + 24; + } + } + if (parser_state_tos->box_com) { + buf_ptr[-2] = 0; + parser_state_tos->n_comment_delta = 1 - count_spaces(1, cur_line); + buf_ptr[-2] = '/'; + } + else { + parser_state_tos->n_comment_delta = 0; + while (*buf_ptr == ' ' || *buf_ptr == '\t') + buf_ptr++; + } + parser_state_tos->comment_delta = 0; + *e_com++ = '/'; /* put '/ *' into buffer */ + *e_com++ = '*'; + if (*buf_ptr != ' ' && !parser_state_tos->box_com) + *e_com++ = ' '; + + *e_com = '\0'; + if (troff) { + now_col = 1; + adj_max_col = 80; + } + else + now_col = count_spaces(parser_state_tos->com_col, s_com); /* figure what column we + * would be in if we + * printed the comment + * now */ + + /* Start to copy the comment */ + + while (1) { /* this loop will go until the comment is + * copied */ + if (*buf_ptr > 040 && *buf_ptr != '*') + parser_state_tos->last_nl = 0; + check_size(com); + switch (*buf_ptr) { /* this checks for various spcl cases */ + case 014: /* check for a form feed */ + if (!parser_state_tos->box_com) { /* in a text comment, break the line here */ + parser_state_tos->use_ff = true; + /* fix so dump_line uses a form feed */ + dump_line(); + last_bl = 0; + *e_com++ = ' '; + *e_com++ = '*'; + *e_com++ = ' '; + while (*++buf_ptr == ' ' || *buf_ptr == '\t'); + } + else { + if (++buf_ptr >= buf_end) + fill_buffer(); + *e_com++ = 014; + } + break; + + case '\n': + if (had_eof) { /* check for unexpected eof */ + printf("Unterminated comment\n"); + *e_com = '\0'; + dump_line(); + return; + } + one_liner = 0; + if (parser_state_tos->box_com || parser_state_tos->last_nl) { /* if this is a boxed comment, + * we dont ignore the newline */ + if (s_com == e_com) { + *e_com++ = ' '; + *e_com++ = ' '; + } + *e_com = '\0'; + if (!parser_state_tos->box_com && e_com - s_com > 3) { + if (break_delim == 1 && s_com[0] == '/' + && s_com[1] == '*' && s_com[2] == ' ') { + char *t = e_com; + break_delim = 2; + e_com = s_com + 2; + *e_com = 0; + if (blanklines_before_blockcomments) + prefix_blankline_requested = 1; + dump_line(); + e_com = t; + s_com[0] = s_com[1] = s_com[2] = ' '; + } + dump_line(); + check_size(com); + *e_com++ = ' '; + *e_com++ = ' '; + } + dump_line(); + now_col = parser_state_tos->com_col; + } + else { + parser_state_tos->last_nl = 1; + if (unix_comment != 1) { /* we not are in unix_style + * comment */ + if (unix_comment == 0 && s_code == e_code) { + /* + * if it is a UNIX-style comment, ignore the + * requirement that previous line be blank for + * unindention + */ + parser_state_tos->com_col = ((parser_state_tos->ind_level - unindent_displace) + + ind_size); + if (parser_state_tos->com_col <= 1) + parser_state_tos->com_col = 2; + } + unix_comment = 2; /* permanently remember that we are in + * this type of comment */ + dump_line(); + ++line_no; + now_col = parser_state_tos->com_col; + *e_com++ = ' '; + /* + * fix so that the star at the start of the line will line + * up + */ + do /* flush leading white space */ + if (++buf_ptr >= buf_end) + fill_buffer(); + while (*buf_ptr == ' ' || *buf_ptr == '\t'); + break; + } + if (*(e_com - 1) == ' ' || *(e_com - 1) == '\t') + last_bl = e_com - 1; + /* + * if there was a space at the end of the last line, remember + * where it was + */ + else { /* otherwise, insert one */ + last_bl = e_com; + check_size(com); + *e_com++ = ' '; + ++now_col; + } + } + ++line_no; /* keep track of input line number */ + if (!parser_state_tos->box_com) { + int nstar = 1; + do { /* flush any blanks and/or tabs at start of + * next line */ + if (++buf_ptr >= buf_end) + fill_buffer(); + if (*buf_ptr == '*' && --nstar >= 0) { + if (++buf_ptr >= buf_end) + fill_buffer(); + if (*buf_ptr == '/') + goto end_of_comment; + } + } while (*buf_ptr == ' ' || *buf_ptr == '\t'); + } + else if (++buf_ptr >= buf_end) + fill_buffer(); + break; /* end of case for newline */ + + case '*': /* must check for possibility of being at end + * of comment */ + if (++buf_ptr >= buf_end) /* get to next char after * */ + fill_buffer(); + + if (unix_comment == 0) /* set flag to show we are not in + * unix-style comment */ + unix_comment = 1; + + if (*buf_ptr == '/') { /* it is the end!!! */ + end_of_comment: + if (++buf_ptr >= buf_end) + fill_buffer(); + + if (*(e_com - 1) != ' ' && !parser_state_tos->box_com) { /* insure blank before + * end */ + *e_com++ = ' '; + ++now_col; + } + if (break_delim == 1 && !one_liner && s_com[0] == '/' + && s_com[1] == '*' && s_com[2] == ' ') { + char *t = e_com; + break_delim = 2; + e_com = s_com + 2; + *e_com = 0; + if (blanklines_before_blockcomments) + prefix_blankline_requested = 1; + dump_line(); + e_com = t; + s_com[0] = s_com[1] = s_com[2] = ' '; + } + if (break_delim == 2 && e_com > s_com + 3 + /* now_col > adj_max_col - 2 && !parser_state_tos->box_com */ ) { + *e_com = '\0'; + dump_line(); + now_col = parser_state_tos->com_col; + } + check_size(com); + *e_com++ = '*'; + *e_com++ = '/'; + *e_com = '\0'; + parser_state_tos->just_saw_decl = l_just_saw_decl; + return; + } + else { /* handle isolated '*' */ + *e_com++ = '*'; + ++now_col; + } + break; + default: /* we have a random char */ + if (unix_comment == 0 && *buf_ptr != ' ' && *buf_ptr != '\t') + unix_comment = 1; /* we are not in unix-style comment */ + + *e_com = *buf_ptr++; + if (buf_ptr >= buf_end) + fill_buffer(); + + if (*e_com == '\t') /* keep track of column */ + now_col = ((now_col - 1) & tabmask) + tabsize + 1; + else if (*e_com == '\b') /* this is a backspace */ + --now_col; + else + ++now_col; + + if (*e_com == ' ' || *e_com == '\t') + last_bl = e_com; + /* remember we saw a blank */ + + ++e_com; + if (now_col > adj_max_col && !parser_state_tos->box_com && unix_comment == 1 && e_com[-1] > ' ') { + /* + * the comment is too long, it must be broken up + */ + if (break_delim == 1 && s_com[0] == '/' + && s_com[1] == '*' && s_com[2] == ' ') { + char *t = e_com; + break_delim = 2; + e_com = s_com + 2; + *e_com = 0; + if (blanklines_before_blockcomments) + prefix_blankline_requested = 1; + dump_line(); + e_com = t; + s_com[0] = s_com[1] = s_com[2] = ' '; + } + if (last_bl == 0) { /* we have seen no blanks */ + last_bl = e_com; /* fake it */ + *e_com++ = ' '; + } + *e_com = '\0'; /* print what we have */ + *last_bl = '\0'; + while (last_bl > s_com && last_bl[-1] < 040) + *--last_bl = 0; + e_com = last_bl; + dump_line(); + + *e_com++ = ' '; /* add blanks for continuation */ + *e_com++ = ' '; + *e_com++ = ' '; + + t_ptr = last_bl + 1; + last_bl = 0; + if (t_ptr >= e_com) { + while (*t_ptr == ' ' || *t_ptr == '\t') + t_ptr++; + while (*t_ptr != '\0') { /* move unprinted part of + * comment down in buffer */ + if (*t_ptr == ' ' || *t_ptr == '\t') + last_bl = e_com; + *e_com++ = *t_ptr++; + } + } + *e_com = '\0'; + now_col = count_spaces(parser_state_tos->com_col, s_com); /* recompute current + * position */ + } + break; + } + } +} diff --git a/src/util/indent/version.h b/src/util/indent/version.h new file mode 100644 index 0000000..c5e7a00 --- /dev/null +++ b/src/util/indent/version.h @@ -0,0 +1,2 @@ +#define VERSION_STRING \ +"GNU indent 1.0. Based on Berkeley indent 5.11 (9/15/88)." diff --git a/src/util/indent/wrapper b/src/util/indent/wrapper new file mode 100644 index 0000000..0a75a43 --- /dev/null +++ b/src/util/indent/wrapper @@ -0,0 +1,11 @@ +#!/bin/sh +MUDLIB=/user/mud/mudlib +case $1 in + /* | *..*) + echo illegal ;; + *) + if test -n "`echo $1 | sed 's/[a-zA-Z0-9._#%/]//g'`"; then + echo illegal; exit 1 + fi + /user/mud/bin/indent ${MUDLIB}/$1 -lpc;; +esac diff --git a/src/util/xerq/DONE b/src/util/xerq/DONE new file mode 100644 index 0000000..effcac9 --- /dev/null +++ b/src/util/xerq/DONE @@ -0,0 +1,40 @@ +Version 1.1 +~~~~~~~~~~~ +Bug fixes. +Added ERQ_LOOKUP, hostname => ipnumber resolving (opposite of ERQ_RLOOKUP) +Added an lpc socket daemon + +Version 1.2 +~~~~~~~~~~~ +Fixed DETACH +Fixed small problem with ifinger +Added random interval for sequential part of erq tickets. +Added socket_transfer and socket_address to socketd +Changed socketd to bind sockets to object the callback closure is bound to. +Added some docs for the socketd. + +Version 1.2a +~~~~~~~~~~~~ +Fixed crasher and wrong return value in remove_child() + +Version 1.3 +~~~~~~~~~~~ +Fixed driver -> erq socket blocking. +Increased driver -> erq buffer size. (optional driver diff) +Rewrote lpc ifinger and telnet. +Fixed error reply from socketd. + +Version 1.3a +~~~~~~~~~~~~ +Fixed problems with alignment of integers on some platforms (hpux, solaris, + probably more). +New configure script. +Properly handles change in 3.2.1@120 with random.c + +Version 1.4 +~~~~~~~~~~~ +Now operates fully asynchronously. Instead of returning EWOULDBLOCK, data + is queued and sent when socket unblocks. +Erq->driver socket is nonblocking now, uses queue mechanism described above. +Rewrote erq->driver reply routines. +Reincluded driver patch (oops ;) diff --git a/src/util/xerq/Makefile b/src/util/xerq/Makefile new file mode 100644 index 0000000..0ceee02 --- /dev/null +++ b/src/util/xerq/Makefile @@ -0,0 +1,73 @@ + +# These lines are needed on some machines. +MAKE=make +SHELL=/bin/sh +INSTALL=/usr/bin/install -c +mkinstalldirs=$(SHELL) ../../mkinstalldirs +# +CC=gcc -std=gnu99 + +prefix=/opt/psyced +exec_prefix=${prefix} + +SUBDIRS = +SED = sed + +BINDIR=/opt/psyced/bin +MUD_LIB=/opt/psyced/world +ERQ_DIR=/opt/psyced/run + + +#PROFIL= -DOPCPROF -DVERBOSE_OPCPROF +#PROFIL=-p -DMARK +#PROFIL=-pg +PROFIL= +#Enable warnings from the compiler, if wanted. +WARN= # no warning options - will work with all compilers :-) +#WARN= -Wall -Wshadow -Dlint +#WARN= -Wall -Wshadow -Wno-parentheses # gcc settings +# +# Optimization and source level debugging options. +# adding a -fomit-frame-pointer on the NeXT (gcc version 1.93 (68k, MIT syntax)) +# will corrupt the driver. +HIGH_OPTIMIZE = -O4 -fomit-frame-pointer -g # high optimization +MED_OPTIMIZE= -O2 -g # medium optimization +LOW_OPTIMIZE = -O -g # minimal optimization +NO_OPTIMIZE= -g # no optimization; for frequent recompilations. + +OPTIMIZE= $(MED_OPTIMIZE) + +# The main debugging level is define in config.h +# Add additional options here. +DEBUG= +# +MPATH=-I../.. -DMUD_LIB='"$(MUD_LIB)"' -DBINDIR='"$(BINDIR)"' -DERQ_DIR='"$(ERQ_DIR)"' +# +CFLAGS= $(OPTIMIZE) $(DEBUG) $(WARN) $(MPATH) $(PROFIL) +# +LIBS=-lnsl -lm -lresolv +# +LDFLAGS=-L/L/depot/lib + +OBJ = erq.o execute.o socket.o lookup.o + +erq: $(OBJ) + $(CC) $(CFLAGS) $(LDFLAGS) $(OBJ) -o $@ $(LIBS) + +%.o : %.c + $(CC) -I../.. $(CFLAGS) -c $< -o $@ + +*.o: erq.h defs.h \ + ../../config.h \ + ../../machine.h \ + ../../port.h + +install: erq + $(mkinstalldirs) $(BINDIR) $(ERQ_DIR) + $(INSTALL) erq $(BINDIR)/erq + +clean: + rm -f erq *.o *~ + +realclean: clean + diff --git a/src/util/xerq/Makefile.in b/src/util/xerq/Makefile.in new file mode 100644 index 0000000..0383f24 --- /dev/null +++ b/src/util/xerq/Makefile.in @@ -0,0 +1,73 @@ + +# These lines are needed on some machines. +MAKE=make +SHELL=@CONFIG_SHELL@ +INSTALL=@INSTALL@ +mkinstalldirs=$(SHELL) @top_srcdir@/mkinstalldirs +# +CC=@CC@ + +prefix=@prefix@ +exec_prefix=@exec_prefix@ + +SUBDIRS = +SED = sed + +BINDIR=@bindir@ +MUD_LIB=@libdir@ +ERQ_DIR=@libexecdir@ + + +#PROFIL= -DOPCPROF -DVERBOSE_OPCPROF +#PROFIL=-p -DMARK +#PROFIL=-pg +PROFIL= +#Enable warnings from the compiler, if wanted. +WARN= # no warning options - will work with all compilers :-) +#WARN= -Wall -Wshadow -Dlint +#WARN= -Wall -Wshadow -Wno-parentheses # gcc settings +# +# Optimization and source level debugging options. +# adding a -fomit-frame-pointer on the NeXT (gcc version 1.93 (68k, MIT syntax)) +# will corrupt the driver. +HIGH_OPTIMIZE = @OCFLAGS@ # high optimization +MED_OPTIMIZE= @MCFLAGS@ # medium optimization +LOW_OPTIMIZE = @LCFLAGS@ # minimal optimization +NO_OPTIMIZE= @DCFLAGS@ # no optimization; for frequent recompilations. + +OPTIMIZE= $(@val_optimize@_OPTIMIZE) + +# The main debugging level is define in config.h +# Add additional options here. +DEBUG= +# +MPATH=-I../.. -DMUD_LIB='"$(MUD_LIB)"' -DBINDIR='"$(BINDIR)"' -DERQ_DIR='"$(ERQ_DIR)"' +# +CFLAGS= @EXTRA_CFLAGS@ $(OPTIMIZE) $(DEBUG) $(WARN) $(MPATH) $(PROFIL) +# +LIBS=@ERQ_LIBS@ +# +LDFLAGS=@LDFLAGS@ + +OBJ = erq.o execute.o socket.o lookup.o + +erq@EXEEXT@: $(OBJ) + $(CC) $(CFLAGS) $(LDFLAGS) $(OBJ) -o $@ $(LIBS) + +%.o : %.c + $(CC) -I@top_srcdir@ $(CFLAGS) -c $< -o $@ + +*.o: erq.h defs.h \ + @top_srcdir@/config.h \ + @top_srcdir@/machine.h \ + @top_srcdir@/port.h + +install: erq@EXEEXT@ + $(mkinstalldirs) $(BINDIR) $(ERQ_DIR) + $(INSTALL) erq@EXEEXT@ $(BINDIR)/erq@EXEEXT@ + +clean: + rm -f erq@EXEEXT@ *.o *~ + +realclean: clean + diff --git a/src/util/xerq/README b/src/util/xerq/README new file mode 100644 index 0000000..b0f04ca --- /dev/null +++ b/src/util/xerq/README @@ -0,0 +1,23 @@ +XErq - Copyright 1995 by Brian Gerst (Garion@Timewarp). +Based on the standard erq demon for LPmud 3.2.1 by Joern Rennecke. + +Source code herein refers to the source code, and any executables +created from the same source code. + +All rights reserved. Permission is granted to extend and modify the +source code provided subject to the restriction that the source code may +not be used in any way whatsoever for monetary gain. + +****************************** + +This is a replacement for the erq demon that comes standard with the +driver. It differs from the standard erq in that it doesn't make use +of subservers, which can cause zombie processes. + +The socketd will need the following privileges from +master->privilege_violation(): + "erq" + "bind_lambda" + +Any bug/questions/comments, mail to bgerst@quark.gmi.edu or the +maintainer of the driver. diff --git a/src/util/xerq/defs.h b/src/util/xerq/defs.h new file mode 100644 index 0000000..1f6bde5 --- /dev/null +++ b/src/util/xerq/defs.h @@ -0,0 +1,271 @@ +#ifndef XERQ_DEFS_H__ +#define XERQ_DEFS_H__ 1 + +/* Standard include for all modules of xerq containing all possible + * system includes, datatypes and external definitions. + */ + +#include "driver.h" + +#ifndef ERQ_DEBUG +# define ERQ_DEBUG 0 +#endif + +#ifdef USE_IPV6 +# define __IPV6__ +#endif + +#include "erq.h" + +#include +#include +#ifdef HAVE_SYS_TIME_H +# include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef _AIX +# include +#endif + +#ifdef WEXITSTATUS +typedef int wait_status_t; +#else +typedef union wait wait_status_t; +#define WEXITSTATUS(status) ((status).w_retcode) +#define WTERMSIG(status) ((status).w_termsig) +#endif + +#ifndef SIGCLD +# define SIGCLD SIGCHLD +#endif + +#ifndef SIGKILL +# define SIGKILL 9 +#endif +#ifndef SIGTERM +# define SIGTERM 15 +#endif + +#define randomize(n) srandom(n) +#define get_ticket() (random() & 0x7FFFFFFF) + +#ifdef TIOCNOTTY +# define DETACH +#endif + +#ifndef ERQ_MAX_SEND +# define ERQ_MAX_SEND 256 +#endif + +/* --- Types --- */ + +typedef struct ticket_s ticket_t; +typedef struct equeue_s equeue_t; +typedef struct socket_s socket_t; +typedef struct child_s child_t; +typedef struct auth_s auth_t; +typedef struct retry_s retry_t; + +/* --- struct ticket_s + * Tickets are used to identify tasks and consist of a computed + * and a random number. + */ + +struct ticket_s +{ + int32 seq; /* The seq_number assigned to this ticket */ + int32 rnd; /* A random number generated for this ticket */ +}; + +#define TICKET_SIZE sizeof(struct ticket_s) + +/* --- struct equeue_s: one (pending) message + * + * We can't call this queue_s/queue_t because Solaris already has + * a datastructure with that name :-( + */ + +struct equeue_s +{ + equeue_t *next; + int pos; /* index of next byte in buf[] to write */ + int len; /* remaining length to write */ + int32 handle; /* message handle for send-ok replys */ + char buf[1]; /* allocated big enough to hold the data */ +}; + +/* --- struct socket_s: one socket descriptor + * This structure is used for explicite TCP/UDP communication, as well + * as for the communication with spawned subprograms (then .handle and + * .ticket are copied from the controlling child_t). + */ + +struct socket_s +{ + socket_t *next; + int32 handle; + ticket_t ticket; + char type; /* Type of the socket */ + int fd; /* This socket's fd */ + equeue_t *queue; /* List of messages pending to send */ +}; + +/* Possible socket.types: */ + +#define SOCKET_UDP 1 /* UDP socket */ +#define SOCKET_LISTEN 2 /* Accept-socket waiting for connections */ +#define SOCKET_CONNECTED 3 /* Connected TCP socket */ +#define SOCKET_WAIT_ACCEPT 4 /* Accept-socket with connection pending */ +#define SOCKET_WAIT_CONNECT 5 /* TCP socket while connecting */ +#define SOCKET_STDOUT 6 /* Command: stdio socket */ +#define SOCKET_STDERR 7 /* Command: stderr socket */ +#define SOCKET_WAIT_AUTH 8 /* authd-socket while connecting */ +#define SOCKET_AUTH 9 /* authd-socket */ + +/* --- struct child_s + * Child structures are used for executed and spawned commands. + */ + +struct child_s +{ + child_t *next; + int32 handle; + ticket_t ticket; + char type; /* Type of the child */ + char status; /* child status */ + pid_t pid; /* PID of the child process */ + wait_status_t return_code; /* exitstatus returned by wait() */ + socket_t *fd; /* NULL or the stdio fd */ + socket_t *err; /* NULL or the stderr fd */ +}; + +/* Values for child_t.type */ + +#define CHILD_EXECUTE 1 +#define CHILD_SPAWN 2 +#define CHILD_FORK 3 + +/* Values for child_t.status */ + +#define CHILD_RUNNING 1 /* Child is being started up or running */ +#define CHILD_EXITED 2 /* Child exited */ + +/* --- struct auth_s: one auth_d query + * auth_t is treated as subclass of socket_t. + */ + +struct auth_s +{ + socket_t s; /* The subclassed socket_t */ + int32 local_port; /* Our port of the connection */ + int32 remote_port; /* Remote port of the connection */ + char buf[ERQ_MAX_REPLY]; /* Buffer for the reply */ + int pos; /* Position in .buf */ +}; + +#define AUTH_PORT 113 + +/* --- struct retry_s + * List of function calls to retry at a given time. + */ + +struct retry_s +{ + retry_t *next; + time_t time; /* time() when this should be tried */ + void (*func)(char *, int); + /* Function to call as: (*func)(.mesg, read_32(.mesg)) + */ + char mesg[1]; + /* Allocated big enough, this is the data for .func. + */ +}; + + +/* --- Variables --- */ + +extern const char * erq_dir; +extern child_t *childs; +extern socket_t *sockets; +extern int seq_number, seq_interval; +extern pid_t master_pid; + +/* --- Prototypes --- */ + +extern char *time_stamp(void); +extern void die(void); +extern void bad_request(char *); +extern void erq_cmd(void); +extern void sig_child(); +extern void remove_child(child_t *); +extern int read_socket(socket_t *, int); +extern socket_t *new_socket(int, char); +extern void reply_errno(int32); +extern void reply1(int32, const void *, int32); +extern void reply1keep(int32, const void *, int32); +extern void replyn(int32, int, int, ...); +extern void write1(void *, int); +extern void add_to_queue(equeue_t **, char *, int, int32); +extern int flush_queue(equeue_t **, int, int); +extern void add_retry(void (*func)(char *, int), char *mesg, int len, int t); + +extern void erq_rlookup(char *, int); +extern void erq_execute(char *, int); +extern void erq_fork(char *, int); +extern void erq_auth(char *, int); +extern void erq_spawn(char *, int); +extern void erq_send(char *, int); +extern void erq_kill(char *, int); +extern void erq_open_udp(char *, int); +extern void erq_open_tcp(char *, int); +extern void erq_listen(char *, int); +extern void erq_accept(char *, int); +extern void erq_lookup(char *, int); +#ifdef USE_IPV6 +extern void erq_rlookupv6(char *, int); +#endif + +extern void close_socket(socket_t *); + +/* --- Debug Functions --- */ + +#if ERQ_DEBUG > 1 +# define XPRINTF(x) fprintf x +#else +# define XPRINTF(x) +#endif + +/* --- Inline Functions --- */ + +static INLINE int32 +read_32(char *a) +{ + int32 x; + memcpy(&x, a, sizeof(x)); + return ntohl(x); +} + +static INLINE void +write_32(char *a, int32 i) +{ + i=htonl(i); + memcpy(a, &i, sizeof(i)); +} + +#define get_handle(x) read_32((x)+4) + +#endif /* XERQ_DEFS_H__ */ + diff --git a/src/util/xerq/docs/socketd/socket_accept b/src/util/xerq/docs/socketd/socket_accept new file mode 100644 index 0000000..6e9b1d3 --- /dev/null +++ b/src/util/xerq/docs/socketd/socket_accept @@ -0,0 +1,28 @@ +SYNOPSIS + int socket_accept(int fd, closure callback, int|void opts) + + void callback(int fd, int action, mixed a, mixed b) + +DESCRIPTION + Acknowledges an incoming tcp connection to a listening port. + Returns the file descriptor for the new socket. + +CALLBACK + SOCKET_READY + The socket is connected and ready to be written to/read from. + + SOCKET_READ + Output from the socket + A contains the data from the socket either as an int* or a string + depending on the option SOCKET_BINARY + + SOCKET_CLOSE + The socket has closed. + + SOCKET_ERROR + An error has been detected on the socket. + A contains the error code obtained from the erq daemon. + B contains the value of errno in most cases. + +SEE ALSO + sockets, socket_listen(), socket_write(), socket_close() diff --git a/src/util/xerq/docs/socketd/socket_address b/src/util/xerq/docs/socketd/socket_address new file mode 100644 index 0000000..ef53771 --- /dev/null +++ b/src/util/xerq/docs/socketd/socket_address @@ -0,0 +1,12 @@ +SYNOPSIS + mixed socket_address(int fd) + +DESCRIPTION + Returns an array holding the remote host and port (connected tcp + sockets) or the local host and port (listening and udp sockets). + +SEE_ALSO + sockets + + + diff --git a/src/util/xerq/docs/socketd/socket_connect b/src/util/xerq/docs/socketd/socket_connect new file mode 100644 index 0000000..db27e7e --- /dev/null +++ b/src/util/xerq/docs/socketd/socket_connect @@ -0,0 +1,29 @@ +SYNOPSIS + int socket_connect(string host, int port, closure callback, + int|void opts) + + void callback(int fd, int action, mixed a, mixed b) + +DESCRIPTION + Opens an outgoing tcp connection. Returns the file descriptor + for the socket. + +CALLBACK + SOCKET_READY + The socket is connected and ready to be written to/read from. + + SOCKET_READ + Output from the socket + A contains the data from the socket either as an int* or a string + depending on the option SOCKET_BINARY + + SOCKET_CLOSE + The socket has closed. + + SOCKET_ERROR + An error has been detected on the socket. + A contains the error code obtained from the erq daemon. + B contains the value of errno in most cases. + +SEE ALSO + sockets, socket_listen(), socket_wrtie(), socket_close() diff --git a/src/util/xerq/docs/socketd/socket_listen b/src/util/xerq/docs/socketd/socket_listen new file mode 100644 index 0000000..759e83d --- /dev/null +++ b/src/util/xerq/docs/socketd/socket_listen @@ -0,0 +1,27 @@ +SYNOPSIS + int socket_listen(int port, closure callback) + + void callback(int fd, int action, mixed a, mixed b) + +DESCRIPTION + Opens a tcp port for listening. Returns the file descriptor + for the socket. + +CALLBACK + SOCKET_READY + The socket is open and awaiting connections. + + SOCKET_ACCEPT + An incoming connection has been deteced on the socket, accept + it with socket_accept(). + + SOCKET_CLOSE + The socket has closed. + + SOCKET_ERROR + An error has been detected on the socket. + A contains the error code obtained from the erq daemon. + B contains the value of errno in most cases. + +SEE ALSO + sockets, socket_accept(), socket_close() diff --git a/src/util/xerq/docs/socketd/socket_sendto b/src/util/xerq/docs/socketd/socket_sendto new file mode 100644 index 0000000..be11040 --- /dev/null +++ b/src/util/xerq/docs/socketd/socket_sendto @@ -0,0 +1,8 @@ +SYNOPSIS + int socket_sendto(int fd, string host, int port, int*|string mesg) + +DESCRIPTION + Sends a datagram to the remote host. + +SEE ALSO + sockets, socket_udp(), socket_close() diff --git a/src/util/xerq/docs/socketd/socket_transfer b/src/util/xerq/docs/socketd/socket_transfer new file mode 100644 index 0000000..8e11030 --- /dev/null +++ b/src/util/xerq/docs/socketd/socket_transfer @@ -0,0 +1,9 @@ +SYNOPSIS + int socket_transfer(int fd, closure transfer_func) + +DESCRIPTION + Transfers a socket to another object/callback. + Transfer_func has to return the new callback or the transfer fails. + +SEE_ALSO + sockets diff --git a/src/util/xerq/docs/socketd/socket_udp b/src/util/xerq/docs/socketd/socket_udp new file mode 100644 index 0000000..22831d0 --- /dev/null +++ b/src/util/xerq/docs/socketd/socket_udp @@ -0,0 +1,29 @@ +SYNOPSIS + int socket_udp(int port, closure callback, int|void opts) + + void callback(int fd, int action, mixed a, mixed b, mixed c) + +DESCRIPTION + Opens a udp datagram port. Returns the file descriptor for + the socket. + +CALLBACK + SOCKET_READY + The socket is open and awaiting connections. + + SOCKET_READ + An incoming datagram has been received. + A contains the message. + B contains the remote host. + C contains the remote port. + + SOCKET_CLOSE + The socket has closed. + + SOCKET_ERROR + An error has been detected on the socket. + A contains the error code obtained from the erq daemon. + B contains the value of errno in most cases. + +SEE ALSO + sockets, socket_sendto(), socket_close() diff --git a/src/util/xerq/docs/socketd/socket_write b/src/util/xerq/docs/socketd/socket_write new file mode 100644 index 0000000..a8fd4a9 --- /dev/null +++ b/src/util/xerq/docs/socketd/socket_write @@ -0,0 +1,8 @@ +SYNOPSIS + int socket_write(int fd, int*|string mesg) + +DESCRIPTION + Sends the message out onto a tcp connection. + +SEE ALSO + sockets, socket_listen(), socket_connect(), socket_close() diff --git a/src/util/xerq/erq.c b/src/util/xerq/erq.c new file mode 100644 index 0000000..df6b8e4 --- /dev/null +++ b/src/util/xerq/erq.c @@ -0,0 +1,829 @@ +/*--------------------------------------------------------------------------- + * XErq - Main module. + * (C) Copyright 1995 by Brian Gerst. + * (C) Copyright 2001 by Brian Gerst, Frank Kirschner, Lars Duening. + *--------------------------------------------------------------------------- + * This module implements the main() function with the central loop, plus + * a bunch of utility functions. + * + * Dispatch of the various ERQ requests is implemented with a lookup table + * holding the addresses of the request functions. + *--------------------------------------------------------------------------- + */ + +#include "defs.h" + +/*-------------------------------------------------------------------------*/ +void (*erq_table[])(char *, int) + = { erq_rlookup + , erq_execute + , erq_fork + , erq_auth + , erq_spawn + , erq_send + , erq_kill + , erq_open_udp + , erq_open_tcp + , erq_listen + , erq_accept + , erq_lookup +#ifdef USE_IPV6 + , erq_rlookupv6 +#endif +}; + /* Dispatchtable for the ERQ request functions. + * Arguments are (message, msg_len). + */ + +#ifndef USE_IPV6 +# define ERQ_REQUEST_MAX ERQ_LOOKUP +#else +# define ERQ_REQUEST_MAX ERQ_RLOOKUPV6 +#endif + +/*-------------------------------------------------------------------------*/ +const char * erq_dir = ERQ_DIR; + /* The filename of the directory with the ERQ executables. */ + +child_t *childs; + /* List of active children. The main loop will remove _EXITED children. + */ + +socket_t *sockets; + /* List of opened sockets, including those to communicate with spawned + * commands. + */ + +retry_t *retries; + /* List of function calls to retry at a later point of time. + */ + +equeue_t *stdout_queue; + /* List of messages pending to write to stdout. + */ + +int in_select; + /* TRUE while erq is in select() - during this time sig_child() + * can write its replies directly. + */ + +int seq_number; + /* The last sequence number assigned to ticket, incremented + * in s, initialized with a random number. + */ + +int seq_interval; + /* The interval used to increment seq_number, initialized with + * an odd random number. + */ + +pid_t master_pid; + /* The pid of the 'master' erq process. + */ + +/* When spawning a short-running child process, it used to happen that the + * process finishes before the parent even manages to put the pid into + * the child control structure; causing sig_child() not to find the child + * structure when it gets the signal. + * To avoid this, the spawning code employs a synchronisation scheme to + * make sure that the child doesn't execute before the parent completed + * initialisation. + * + * For ERQ_FORKed children (which are not synchronized), and as a fallback + * solution in case the synchronisation fails and the child terminates + * prematurely, sig_child() stores the relevant data in these globals for + * the main process to evaluate. The calling pattern (one ERQ + * command per select() round) guarantees that there can be only one such + * 'unfinished' child control structure at a time. + */ + +volatile int pending_sig; + /* Set to true if these variables hold data of for an unaccounted SIG_CLD. + */ + +volatile wait_status_t pending_status; +volatile pid_t pending_pid; + /* The status and pid for the pending SIG_CLD, valid only while pending_sig + * is TRUE. + */ + +/*-------------------------------------------------------------------------*/ +char * +time_stamp (void) + +/* Return a textual representation of the current time + * in the form "YYYY.MM.DD HH:MM:SS [xerq]". + * Result is a pointer to a static buffer. + * + * Putting this function in strfuns is not a good idea, because + * it is need by almost every module anyway. + */ + +{ + time_t t; + static char result[27+20]; + struct tm *tm; + int pid; + + t = time(NULL); + tm = localtime(&t); + pid = getpid(); + if (pid == master_pid) + strftime(result, sizeof(result), "%Y.%m.%d %H:%M:%S [xerq]", tm); + else + { + strftime(result, sizeof(result), "%Y.%m.%d %H:%M:%S [xerq:", tm); + sprintf(result+26, "%d]", pid); + } + return result; +} /* time_stamp() */ + +/*-------------------------------------------------------------------------*/ +int +main(int argc, char *argv[]) + +/* The main program and -loop of the ERQ. + */ + +{ + int num; + + master_pid = getpid(); + + /* Print information about this daemon to help debugging */ + { + fprintf(stderr, "%s XERQ %s: Path '%s', debuglevel %d\n" + , time_stamp(), __DATE__, argv[0], ERQ_DEBUG + ); + } + + /* Quick and dirty commandline parser */ + { + int is_forked = 0; + int i; + + for (i = 1; i < argc; i++) + { + if (!strcmp(argv[i], "--forked")) + is_forked = 1; + else if (!strcmp(argv[i], "--execdir")) + { + if (i+1 >= argc) + { + fprintf(stderr, "%s Missing value for --execdir.\n" + , time_stamp()); + die(); + } + erq_dir = argv[i+1]; + i++; + } + else + { + fprintf(stderr, "%s Unknown argument '%s'.\n" + , time_stamp(), argv[i]); + die(); + } + } + /* Check if we have been forked off the driver */ + if (is_forked) + { + write(1, "1", 1); /* indicate sucessful fork/execl */ + fprintf(stderr, "%s Demon started\n", time_stamp() ); + } + else + { + fprintf(stderr, "%s Dynamic attachement unimplemented\n" + , time_stamp()); + die(); + } + } + + /* Initialize */ + + in_select = 0; + pending_sig = 0; + + signal(SIGCLD, sig_child); + signal(SIGPIPE, SIG_IGN); + + sockets = NULL; + childs = NULL; + retries = NULL; + stdout_queue = NULL; + + randomize(time(0)); + seq_number = get_ticket(); + seq_interval = get_ticket() | 1; /* make sure it is odd */ + +#ifdef DETACH + /* Detach from console */ + num = open("/dev/tty", O_RDWR); + if (num >= 0) { + ioctl(num, TIOCNOTTY, 0); + close(num); + } +#endif + + /* The main loop */ + + while(1) + { + fd_set read_fds, write_fds; + int num_fds; + child_t *chp; + retry_t *rtp, **rtpp; + socket_t *sp; + struct timeval timeout; + + /* Clean up the list of children (may close some sockets) */ + + for (chp = childs; chp;) + { + child_t *this = chp; + + chp = chp->next; + + /* If there is a pending SIG_CLD for this child, handle it. + * This is to be expected for CHILD_FORK children. + */ + if (pending_sig && this->pid == pending_pid) + { + if (this->type != CHILD_FORK) + fprintf(stderr, "%s Pending SIG_CLD for pid %d delivered.\n" + , time_stamp(), pending_pid); + this->status = pending_status; + this->pid = pending_pid; + pending_sig = 0; + } + + if (this->status == CHILD_EXITED) + { + XPRINTF((stderr, "%s Child %p exited.\n", time_stamp(), this)); + remove_child(this); /* will also unlink it from the list */ + } + } + + /* look for sockets to select on */ + + FD_ZERO(&read_fds); + FD_ZERO(&write_fds); + + FD_SET(0, &read_fds); + if (stdout_queue) + FD_SET(1, &write_fds); + + num_fds = 2; + for (sp = sockets; sp; sp = sp->next) + { + switch(sp->type) + { + case SOCKET_WAIT_CONNECT: + case SOCKET_WAIT_AUTH: + FD_SET(sp->fd, &write_fds); + FD_SET(sp->fd, &read_fds); + if (sp->fd >= num_fds) + num_fds=sp->fd+1; + break; + + default: + FD_SET(sp->fd, &read_fds); + if (sp->fd >= num_fds) + num_fds=sp->fd+1; + break; + + case SOCKET_WAIT_ACCEPT: + /* do nothing */; + /* Without the ; above, Metrowerks Codewarrior reports + * an error :-( */ + } + + if (sp->queue) + FD_SET(sp->fd, &write_fds); + } /* for (sockets) */ + + /* Scan the list of pending retries for the soonest one. + * Put the time till then into timeout. + * (If the list is empty, select() will receive NULL for timeout). + */ + if (retries) + { + time_t t; + + t = retries->time; + for (rtp = retries; rtp; rtp = rtp->next) + { + if (rtp->time < t) + t = rtp->time; + } + timeout.tv_sec = t - time(NULL); + timeout.tv_usec = 0; + XPRINTF((stderr, "%s Soonest retry_t: in %ld seconds.\n" + , time_stamp(), (long)timeout.tv_sec)); + + if (timeout.tv_sec < 0) + timeout.tv_sec = 0; + } + +#if ERQ_DEBUG > 1 + fprintf(stderr, "%s select()\n", time_stamp()); +#endif + in_select = 1; /* so sig_child() can write reply directly */ + num = select(num_fds, &read_fds, &write_fds, 0, retries ? &timeout : 0); + in_select = 0; /* don't want sig_child() writing now */ + +#if ERQ_DEBUG > 1 + { + int myerrno = errno; + fprintf(stderr, "%s select() returns %d, time() %ld\n" + , time_stamp(), num, (long)time(NULL)); + errno = myerrno; + } +#endif + +#if ERQ_DEBUG > 0 + if (num < 0) + /* Give an error now, but don't abort this loop, + * because the retries have to be handled first. + */ + { + int myerrno = errno; + fprintf(stderr, "%s select() errno = %d", time_stamp(), errno); + errno = myerrno; + perror(" "); + } +#endif + + /* Is stdout ready to write? Then flush the queue. */ + if (num >= 0 && FD_ISSET(1, &write_fds)) + { + XPRINTF((stderr, "%s stdout_queue ready for flush.\n", time_stamp())); + flush_queue(&stdout_queue, 1, 0); + } + + /* Check for retries */ + for (rtpp = &retries; *rtpp; ) + { + rtp = *rtpp; + if (rtp->time <= time(NULL)) + { + XPRINTF((stderr, "%s Call retry %p (time %ld)\n" + , time_stamp(), rtp, (long)rtp->time)); + (*(rtp->func))(rtp->mesg, read_32(rtp->mesg)); + *rtpp = rtp->next; + free(rtp); + } + else + { + rtpp = &rtp->next; + } + } + + /* Error in select */ + if (num < 0) + continue; + + /* check for input from driver */ + if (FD_ISSET(0, &read_fds)) + { + XPRINTF((stderr, "%s New command from driver.\n", time_stamp())); + erq_cmd(); + } + + /* Handle the ready sockets. + * Remember that read_socket() may close the socket. + */ + + for (sp = sockets; sp; ) + { + socket_t *this = sp; + int rc; + + sp = sp->next; + + rc = 0; + + if (FD_ISSET(this->fd, &read_fds)) + { + XPRINTF((stderr, "%s Socket %p (%d) ready for reading.\n" + , time_stamp(), this, this->fd)); + rc = read_socket(this, 0); + } + + if (!rc && FD_ISSET(this->fd, &write_fds)) + { + XPRINTF((stderr, "%s Socket %p (%d) ready for writing.\n" + , time_stamp(), this, this->fd)); + (void)read_socket(this, 1); + } + } + } /* while(1) */ + + /* NOTREACHED */ + + return 0; +} /* main() */ + +/*-------------------------------------------------------------------------*/ +void +erq_cmd (void) + +/* There is data ready from the driver - read and execute it when complete. + * The function maintains a static buffer for the data read - incomplete + * messages are buffered until they are complete. + */ + +{ + static char buf[ERQ_MAX_SEND]; + static int pos = 0; + /* Position in buf[]. If it extends beyond the end of buf, + * it is because the message is too long and the function + * is in the process of skipping the extraneous characters. + */ + + int len, mesg_len; + char request; + + /* Clear the buffer so that errors can be detected more easily */ + memset(buf, 0, sizeof(buf)); + + /* Read the message header */ + if (pos < 9) + { + len = read(0, buf+pos, 9-pos); + if (len <= 0) + { + perror("[xerq] read"); + die(); + } + XPRINTF((stderr, "%s Read %d of the missing %d header bytes.\n" + , time_stamp(), len, 9-pos)); + pos += len; + if (pos < 9) + return; + } + + mesg_len = read_32(buf); + if (mesg_len > sizeof(buf)) + { + /* This doesn't happen in a functioning system */ + fprintf(stderr + , "%s Received too long packet: %d bytes.\n" + , time_stamp(), mesg_len); + die(); + } + + /* Get the rest of the message */ + + if (pos < mesg_len) + { + len = read(0, buf+pos, mesg_len-pos); + if (len <= 0) + { + perror("read"); + die(); + } + XPRINTF((stderr, "%s Read %d of the missing %d message bytes.\n" + , time_stamp(), len, mesg_len-pos)); + pos += len; + if (pos < mesg_len) + return; + } + + XPRINTF((stderr, "%s Message complete.\n", time_stamp())); + pos = 0; /* Message complete */ + + /* Branch on the request */ + request = buf[8]; + if (request <= ERQ_REQUEST_MAX) + { +#if ERQ_DEBUG > 0 + char *mesg, *mesgs[]={ + "rlookup","execute","fork","auth","spawn","send","kill", + "open_udp","open_tcp","listen","accept","lookup", "rlookupv6"}; + mesg=mesgs[(int)request]; + fprintf(stderr, "%s command: %s\n", time_stamp(), mesg); +#endif + (*erq_table[(int)request])(buf, mesg_len); + } + else + bad_request(buf); +} /* erq_cmd() */ + +/*-------------------------------------------------------------------------*/ +void +die(void) + +/* Terminate the ERQ with status 1. + */ + +{ + fprintf(stderr, "%s Demon exiting.\n", time_stamp()); + exit(1); +} /* die() */ + +/*-------------------------------------------------------------------------*/ +#ifndef _AIX +void +sig_child() +#else +void +sig_child(int sig) +#endif + +/* A child process exited - update its child structure. + */ + +{ + wait_status_t status; + pid_t pid; + struct child_s *chp; + + pid = wait(&status); + +#if ERQ_DEBUG > 0 + fprintf(stderr, "%s [sigchild] pid=%d status=%d\n" + , time_stamp(), pid, status); +#endif + + /* Look for the child and mark it as exited */ + for (chp = childs; chp; chp = chp->next) + { + if (chp->pid != pid) + continue; + + chp->status = CHILD_EXITED; + chp->return_code = status; +#if ERQ_DEBUG > 0 + fprintf(stderr, "%s [sigchild] Caught SIGCLD for pid %d, child %p.\n" + , time_stamp(), pid, chp); +#endif + if (in_select) + remove_child(chp); /* safe to do it from here */ + /* if we're in select, we know we're not going to be messing up + the main loop with stuff we're doing here */ + break; + } + + if (!chp) + { + /* There is no valid child. Maybe we caught the signal before + * the child structure was complete (this can happen especially + * with short-lived CHILD_FORK sub processes). + */ + if (pending_sig) + { + fprintf(stderr, "%s [sigchild] SIGCLD for pid %d not delivered.\n" + , time_stamp(), pending_pid); + } + +#if ERQ_DEBUG > 0 + fprintf(stderr, "%s [sigchild] SIGCLD for unknown pid %d received.\n" + , time_stamp(), pid); +#endif + + pending_status = status; + pending_pid = pid; + pending_sig = 1; + } + + /* Restore the signal handler */ + signal(SIGCLD, sig_child); +} /* sig_child() */ + +/*-------------------------------------------------------------------------*/ +void +add_retry (void (*func)(char *, int), char *mesg, int len, int t) + +/* Add a new retry: function is to be executed in seconds + * with (, ) as arguments. + */ + +{ + struct retry_s *retry; + + retry = malloc(sizeof(struct retry_s)+len); + XPRINTF((stderr, "%s New retry %p: %d seconds, func %p, data %p:%d\n" + , time_stamp(), retry, t, func, mesg, len)); + retry->time = time(NULL)+t; + retry->func = func; + memcpy(&retry->mesg, mesg, len); + retry->next = retries; + retries = retry; +} /* add_retry() */ + +/*-------------------------------------------------------------------------*/ +void +bad_request (char *mesg) + +/* ERQ received a bad message in - print some diagnostics. + */ + +{ + fprintf(stderr, "%s Bad request %d\n", time_stamp(), mesg[8]); + fprintf(stderr, "%s %x %x %x %x %x %x %x %x %x\n", time_stamp(), + mesg[0], mesg[1], mesg[2], mesg[3], mesg[4], + mesg[5], mesg[6], mesg[7], mesg[8]); + fprintf(stderr, "%s %c %c %c %c %c %c %c %c %c\n", time_stamp(), + mesg[0], mesg[1], mesg[2], mesg[3], mesg[4], + mesg[5], mesg[6], mesg[7], mesg[8]); + reply1(get_handle(mesg), "", 0); +} /* bad_request() */ + +/*-------------------------------------------------------------------------*/ +void +reply1 (int32 handle, const void *data, int32 len) + +/* Compose a reply message from and the bytes of + * and send it back to the driver. + */ + +{ + char reply[ERQ_MAX_REPLY]; + + write_32(reply, len+8); + write_32(reply+4, handle); + memcpy(reply+8, data, len); + write1(reply, len+8); +} /* reply1() */ + +/*-------------------------------------------------------------------------*/ +void +reply1keep (int32 handle, const void *data, int32 len) + +/* Compose a reply message from and the bytes of + * and send it back to the driver. The message will be an _KEEP_HANDLE + * message. + */ + +{ + char reply[ERQ_MAX_REPLY]; + + write_32(reply, len+12); + write_32(reply+4, ERQ_HANDLE_KEEP_HANDLE); + write_32(reply+8, handle); + memcpy(reply+12, data, len); + write1(reply, len+12); +} /* reply1keep() */ + +/*-------------------------------------------------------------------------*/ +void +replyn (int32 handle, int keep, int num, ...) + +/* Compose and send to the driver a replymessage for with + * the data arguments concatenated as body. If is true, + * a _KEEP_HANDLE message is composed. + * + * Each data argument is a tuple (char *data, int len). + */ + +{ + char reply[ERQ_MAX_REPLY]; + char *p; + int total; + va_list va; + + /* Determine the size of the header */ + total = (keep ? 12 : 8); + p = reply+total; + + /* Catenate the data arguments */ + va_start(va, num); + while (num-- > 0 && total < ERQ_MAX_REPLY) + { + char *data; + int len; + + data = va_arg(va, char *); + len = va_arg(va, int); + if (total + len > ERQ_MAX_REPLY) + { + fprintf(stderr, "%s Too much data in replyn(): %d bytes omitted.\n" + , time_stamp(), total + len - ERQ_MAX_REPLY); + len = ERQ_MAX_REPLY - total; + } + memcpy(p, data, len); + p += len; + total += len; + } + va_end(va); + + if (num > 0) + { + fprintf(stderr, "%s Too much data in replyn(): Remaining %d " + "data blocks omitted.\n" + , time_stamp(), num); + } + + /* Create the header */ + write_32(reply, total); + if (keep) + { + write_32(reply+4, ERQ_HANDLE_KEEP_HANDLE); + write_32(reply+8, handle); + } + else + { + write_32(reply+4, handle); + } + + /* Send the reply */ + write1(reply, total); +} /* replyn() */ + +/*-------------------------------------------------------------------------*/ +void +reply_errno (int32 handle) + +/* Send a (errcode, errno) message to the driver for . + */ + +{ + char mesg[2]; + + switch(errno) + { + case EWOULDBLOCK: +#if EAGAIN != EWOULDBLOCK + case EAGAIN: +#endif + mesg[0] = ERQ_E_WOULDBLOCK; + break; + + case EPIPE: + mesg[0] = ERQ_E_PIPE; + break; + + default: + mesg[0] = ERQ_E_UNKNOWN; + break; + } + mesg[1] = errno; + reply1(handle, mesg, 2); +} /* reply_errno() */ + +/*-------------------------------------------------------------------------*/ +int +writen (int fd, char *mesg, int len, struct equeue_s **qpp) + +/* Send or queue the message (length bytes) to . + * If * is non-NULL, the message is queued immediately. + * Otherwise, the function tries to send as much of the message + * as possible, and the queues whatever is left. + */ + +{ + int l = 0; + + XPRINTF((stderr, "%s writen(%d, %p:%d, %p (-> %p) ))\n" + , time_stamp(), fd, mesg, len, qpp, *qpp)); + if (!(*qpp)) + { + /* Send as much of the message as possible */ + do + l = write(fd, mesg, len); + while (l == -1 && errno == EINTR); + XPRINTF((stderr, "%s Wrote %d bytes.\n", time_stamp(), l)); + if (l < 0 || l == len) + return l; + mesg += l; + len -= l; + } + + if (!len) + return 0; + + XPRINTF((stderr, "%s Queuing data %p:%d\n", time_stamp(), mesg, len)); + add_to_queue(qpp, mesg, len, 0); + return l; +} /* writen() */ + +/*-------------------------------------------------------------------------*/ +void +write1 (void *mesg, int len) + +/* Write the bytes of to stdout, ie to the driver. + */ + +{ + int l; + + l = writen(1, mesg, len, &stdout_queue); + if (l < 0) + { + int myerrno = errno; + fprintf(stderr, "%s Error occurred on driver socket, errno=%d", + time_stamp(), errno); + errno = myerrno; + perror(" "); + die(); + } +#if ERQ_DEBUG > 0 + if (l != len) + fprintf( stderr + , "%s Driver-erq socket blocked, queueing %d bytes\n" + , time_stamp(), len); +#endif +} /* write1() */ + +/***************************************************************************/ + diff --git a/src/util/xerq/erq.h b/src/util/xerq/erq.h new file mode 100644 index 0000000..2adf719 --- /dev/null +++ b/src/util/xerq/erq.h @@ -0,0 +1,59 @@ +/* external request demon interface definitions */ + +#ifndef ERQ_H__ +#define ERQ_H__ 1 + +/* servive request types */ + +#define ERQ_RLOOKUP 0 /* Lookup ip -> name */ +#define ERQ_EXECUTE 1 /* Execute a program */ +#define ERQ_FORK 2 /* Fork a program */ +#define ERQ_AUTH 3 /* Connect to a remote authd */ +#define ERQ_SPAWN 4 /* Spawn a program */ +#define ERQ_SEND 5 /* Send data to a program or connection */ +#define ERQ_KILL 6 /* Kill a program or connection */ +#define ERQ_OPEN_UDP 7 /* Open a UDP socket */ +#define ERQ_OPEN_TCP 8 /* Open a TCP connection */ +#define ERQ_LISTEN 9 /* Open a TCP accept-socket */ +#define ERQ_ACCEPT 10 /* Accept a connection from a accept-socket */ +#define ERQ_LOOKUP 11 /* Lookup name -> ip */ + +#ifdef __IPV6__ +#define ERQ_RLOOKUPV6 12 /* Lookup name/ip6 */ +#endif + +/* Additional service request type flags evaluated by efun send_erq(). + * The ERQ itself won't get to see it. + */ + +#define ERQ_CB_STRING (1 << 31) /* Callback closure takes a string arg */ + + +/* answers from ERQ_EXECUTE / ERQ_FORK */ + +#define ERQ_OK 0 +#define ERQ_SIGNALED 1 +#define ERQ_E_NOTFOUND 2 /* process not found by wait */ +#define ERQ_E_UNKNOWN 3 /* unknown exit condition from wait() */ +#define ERQ_E_ARGLENGTH 4 +#define ERQ_E_ARGFORMAT 5 +#define ERQ_E_ARGNUMBER 6 +#define ERQ_E_ILLEGAL 7 +#define ERQ_E_PATHLEN 8 +#define ERQ_E_FORKFAIL 9 +#define ERQ_E_TICKET 11 +#define ERQ_E_INCOMPLETE 12 +#define ERQ_E_WOULDBLOCK 13 +#define ERQ_E_PIPE 14 +#define ERQ_STDOUT 15 /* Normal data received */ +#define ERQ_STDERR 16 +#define ERQ_EXITED 17 /* Connection closed on EOF */ +#define ERQ_E_NSLOTS 18 + +/* reserved handles */ + +#define ERQ_HANDLE_RLOOKUP (-1) +#define ERQ_HANDLE_KEEP_HANDLE (-2) +#define ERQ_HANDLE_RLOOKUPV6 (-3) + +#endif /* ERQ_H__ */ diff --git a/src/util/xerq/execute.c b/src/util/xerq/execute.c new file mode 100644 index 0000000..88c19d2 --- /dev/null +++ b/src/util/xerq/execute.c @@ -0,0 +1,572 @@ +/*--------------------------------------------------------------------------- + * XErq - Command Execution + * (C) Copyright 1995 by Brian Gerst. + * (C) Copyright 2001 by Brian Gerst, Frank Kirschner, Lars Duening. + *--------------------------------------------------------------------------- + * The functions here implement the subcommand features of the ERQ. + * + * ERQ_EXECUTE and _SPAWN commands are controlled with a child_t structure. + * _SPAWN commands are additionally given two sockets so that the driver + * can communicate with them. + *--------------------------------------------------------------------------- + */ + +#include "defs.h" + +/*-------------------------------------------------------------------------*/ +static int +execute (char *buf, int buflen, char *status, int *esockets, int keep_sockets) + +/* Execute the command (length bytes) and return the pid + * on success, and 0 on failure. * is set to the ERQ_E_ code. + * + * If is non-NULL, it points to an int[4] which is filled + * with two socketpairs to communicate with the execute command: + * esocket[0]: stdin+stdout of the child, closed in the caller + * esocket[2]: stderr of the child, closed in the caller + * esocket[1]: callers socket to stdin+stdout of the child + * esocket[3]: callers socket to stderr of the child + * + * A second purpose of the socketpair is to synchronize the parent with + * the child, so that the child runs after the parent completed the setup. + * + * If the sockets are used for just this purpose, is FALSE + * and the sockets in the child are closed after synchronisation (the caller + * parent has to close its copies, too). If is TRUE, the + * child keeps the sockets and moves them over to the stdio/err channels. + */ + +{ + char path[256], argbuf[1024], *p, *args[96], **argp, c; + pid_t pid; + int quoted; + + XPRINTF((stderr, "%s execute('%s':%d)\n", time_stamp(), buf, buflen)); + + quoted = 0; + status[0] = ERQ_E_FORKFAIL; /* Good default */ + status[1] = 0; + if (buflen >= sizeof argbuf) + { + status[0] = ERQ_E_ARGLENGTH; + return 0; + } + + /* Split the commandline into words, store them in argbuf, and store + * the index pointers in args[]. + * argp points to the args[] slot for the next word; argp[-1] + * is the word currently filled. + */ + argp = &args[0]; + *argp++ = p = argbuf; + while (--buflen >= 0) + { + c = *buf++; + if (c == '\\') + { + if (--buflen >= 0) { + *p++ = *buf++; + } + else + { + status[0] = ERQ_E_ARGFORMAT; + return 0; + } + } + else if (c == '"') + { + quoted = !quoted; + } + else if (isgraph(c) || quoted) + { + *p++ = c; + } + else + { + *p++ = '\0'; + *argp++ = p; + XPRINTF((stderr, "%s arg[%d]: '%s'\n" + , time_stamp(), argp - args - 2, argp[-2])); + if (argp - args >= sizeof args/sizeof args[0]) { + status[0] = ERQ_E_ARGNUMBER; + return 0; + } + while( ( (c = *buf) == ' ' || c == '\t') && --buflen >= 0) + buf++; + } + } + *p++ = '\0'; + *argp++ = 0; + + XPRINTF((stderr, "%s arg[%d]: '%s'\n" + , time_stamp(), argp - args - 2, argp[-2])); + + /* Make sure the command to execute is legal (ie does not try + * get out of its ERQ_DIR sandbox. + */ + p = args[0]; + if (p[0] == '/' || strstr(p, "..")) + { + status[0] = ERQ_E_ILLEGAL; + return 0; + } + if (strlen(erq_dir) + strlen(p) + 2 > sizeof(path)) + { + status[0] = ERQ_E_PATHLEN; + return 0; + } + sprintf(path, "%s/%s", erq_dir, p); + + /* Create the sockets to communicate with the caller */ + if (esockets) + { + if(socketpair(AF_UNIX, SOCK_STREAM, 0, esockets) < 0) + { + perror("socketpair"); + status[0] = ERQ_E_FORKFAIL; + status[1] = errno; + return 0; + } + + if(socketpair(AF_UNIX, SOCK_STREAM, 0, esockets + 2) < 0) + { + perror("socketpair"); + close(esockets[0]); + close(esockets[1]); + status[0] = ERQ_E_FORKFAIL; + status[1] = errno; + return 0; + } + } + + pid = fork(); + if (!pid) + { + /* This is the child */ + + close(0); + close(1); + + if (esockets) + { + char ch, expected; + int num; + + expected = getpid() & 0xff; + XPRINTF((stderr, "%s Child process waits for go-ahead byte '%02x'.\n" + , time_stamp(), expected & 0xff)); + + do { + num = read(esockets[0], &ch, sizeof(c)); + } while (num < 0 && errno == EINTR); + + if (num < 0) + { + int myerrno = errno; + + fprintf(stderr, "%s Child couldn't receive go-ahead byte, errno %d" + , time_stamp(), myerrno); + errno = myerrno; + perror(" "); + } + + if (ch != expected) + { + fprintf(stderr, "%s Child received go-ahead byte '%02x', expected '%02x'\n" + , time_stamp(), ch & 0xff, expected & 0xff); + } + + XPRINTF((stderr, "%s Child resumes.\n", time_stamp())); + + if (keep_sockets) + { + dup2(esockets[0], 0); + dup2(esockets[0], 1); + dup2(esockets[2], 2); + } + close(esockets[0]); + close(esockets[1]); + close(esockets[2]); + close(esockets[3]); + } + + execv(path, args); + _exit(1); + } + + /* This is the caller */ + + XPRINTF((stderr, "%s Forked process %d.\n", time_stamp(), pid)); + + if (esockets) + { + /* Not our sockets */ + close(esockets[0]); + close(esockets[2]); + } + + if (pid < 0) + { + /* Error */ + if (esockets) + { + close(esockets[1]); + close(esockets[3]); + } + status[0] = ERQ_E_FORKFAIL; + status[1] = errno; + return 0; + } + + return pid; +} /* execute() */ + +/*-------------------------------------------------------------------------*/ +static child_t * +new_child (void) + +/* Create a new child_t structure, give it a ticket and add it to + * the childs list. + * Result is the new structure. + */ + +{ + child_t *chp; + + chp = malloc(sizeof(struct child_s)); + XPRINTF((stderr, "%s New child %p.\n", time_stamp(), chp)); + chp->next = childs; + chp->ticket.seq = (seq_number += seq_interval); + chp->ticket.rnd = get_ticket(); + chp->fd = NULL; + chp->err = NULL; + chp->status = CHILD_RUNNING; + chp->pid = 0; + childs = chp; + return chp; +} /* new_child() */ + +/*-------------------------------------------------------------------------*/ +static void +free_child (struct child_s *chp) + +/* Remove the child from the list of childs, if necessary, then + * free the structure. + */ + +{ + child_t **chpp; + int found = 0; + + XPRINTF((stderr, "%s Freeing child %p.\n", time_stamp(), chp)); + for (chpp = &childs; *chpp; chpp=&(*chpp)->next) + { + if (*chpp != chp) + continue; + *chpp = chp->next; + XPRINTF((stderr, "%s Unlinking child %p.\n", time_stamp(), chp)); + found = 1; + break; + } + if (!found) /* child was removed already */ + fprintf(stderr, "%s Child %p to free not found.\n", time_stamp(), chp); + else + free(chp); +} /* free_child() */ + +/*-------------------------------------------------------------------------*/ +void +remove_child (child_t *chp) + +/* The child has exited. Get the exit status and send the proper + * message to the driver, then clean up the child and remove it. + */ + +{ + char mesg[2]; + child_t *chtmp; + int found = 0; + + XPRINTF((stderr, "%s Removing child %p.\n", time_stamp(), chp)); + + for (chtmp = childs; chtmp; chtmp = chtmp->next) + if (chtmp == chp) + { + found = 1; + break; + } + + if (!found) /* child was removed already */ + { + XPRINTF((stderr, "%s Child %p removed already.\n", time_stamp(), chp)); + return; + } + + switch(chp->type) + { + case CHILD_FORK: + case CHILD_EXECUTE: + { + mesg[0] = ERQ_OK; + break; + } + + case CHILD_SPAWN: + { + mesg[0] = ERQ_EXITED; + if (chp->fd) + { + XPRINTF((stderr, "%s Closing 'fd' socket %p\n", time_stamp(), chp->fd)); + if (!read_socket(chp->fd, 0)) + close_socket(chp->fd); + } + if (chp->err) + { + XPRINTF((stderr, "%s Closing 'err' socket %p\n", time_stamp(), chp->err)); + if (!read_socket(chp->err, 0)) + close_socket(chp->err); + } + break; + } + } + + /* Send an exit message for non-forked children */ + if (chp->type != CHILD_FORK) + { + if (WIFEXITED(chp->return_code)) + { + mesg[1] = WEXITSTATUS(chp->return_code); + } + else if (WIFSIGNALED(chp->return_code)) + { + mesg[0] = ERQ_SIGNALED; + mesg[1] = WTERMSIG(chp->return_code); + } + else + { + mesg[0] = ERQ_E_UNKNOWN; + } + XPRINTF((stderr, "%s Sending exit message.\n", time_stamp())); + reply1(chp->handle, mesg, 2); + } + + free_child(chp); +} /* remove_child() */ + +/*-------------------------------------------------------------------------*/ +void +erq_fork (char *mesg, int msglen) + +/* ERQ_FORK: fire-and-(almost)forget a command. + */ + +{ + char status[2]; + child_t *chp; + pid_t pid; + + chp = new_child(); + chp->type = CHILD_FORK; + chp->handle = 0; + + if (0 != (pid = execute(&mesg[9], msglen-9, status, NULL, 0))) + { + chp->pid = pid; + status[0] = ERQ_OK; + } + reply1(get_handle(mesg), status, 2); +} /* erq_fork() */ + +/*-------------------------------------------------------------------------*/ +void +erq_execute (char *mesg, int msglen) + +/* ERQ_EXECUTE: start a command and keep an eye on its progress. + */ + +{ + char status[2]; + int esockets[4]; + pid_t pid; + child_t *chp; + + chp = new_child(); + chp->type = CHILD_EXECUTE; + chp->handle = get_handle(mesg); + + if (0 != (pid = execute(&mesg[9], msglen-9, status, esockets, 0))) + { + char ga_data; + int rc; + + /* The parent */ + chp->pid = pid; + + /* Send the GoAhead signal to the child process */ + ga_data = pid & 0xff; + XPRINTF((stderr, "%s Sending go-ahead byte '%02x' to child.\n" + , time_stamp(), ga_data & 0xff)); + fcntl(esockets[1], F_SETFD, 1); + fcntl(esockets[1], F_SETFL, O_NONBLOCK); + do { + rc = write(esockets[1], &ga_data, sizeof(ga_data)); + } while (rc < 0 && errno == EINTR); + + if (rc < 0) + { + int myerrno = errno; + + fprintf(stderr, "%s Couldn't send go-ahead byte '%02x' to child %p, errno %d" + , time_stamp(), ga_data & 0xff, chp, myerrno); + errno = myerrno; + perror(" "); + } + + /* We don't need the sockets anymore */ + close(esockets[1]); + close(esockets[3]); + return; + } + + free_child(chp); /* Don't need this in the child process */ + reply1(get_handle(mesg), status, 2); +} /* erq_execute() */ + +/*-------------------------------------------------------------------------*/ +void +erq_spawn (char *mesg, int msglen) + +/* ERQ_SPAWN: start a command and communicate with it. + */ + +{ + int esockets[4]; + char status[2]; + pid_t pid; + + child_t *chp; + + /* Set up the child */ + chp = new_child(); + chp->type = CHILD_SPAWN; + chp->handle = get_handle(mesg); + + if (0 != (pid = execute(&mesg[9], msglen-9, status, esockets, 1))) + { + char ga_data; + int rc; + + /* The parent */ + chp->pid = pid; + + /* Make a socket for the stdio */ + chp->fd = new_socket(esockets[1], SOCKET_STDOUT); + memcpy(&chp->fd->ticket, &chp->ticket, TICKET_SIZE); + fcntl(esockets[1], F_SETFD, 1); + fcntl(esockets[1], F_SETFL, O_NONBLOCK); + chp->fd->handle = chp->handle; + + /* Make a socket for the stderr */ + chp->err = new_socket(esockets[3], SOCKET_STDERR); + fcntl(esockets[3], F_SETFD, 1); + fcntl(esockets[3], F_SETFL, O_NONBLOCK); + chp->err->handle = chp->handle; + + /* Send the GoAhead signal to the child process */ + ga_data = pid & 0xff; + XPRINTF((stderr, "%s Sending go-ahead byte '%02x' to child.\n" + , time_stamp(), ga_data)); + do { + rc = write(esockets[1], &ga_data, sizeof(ga_data)); + } while (rc < 0 && errno == EINTR); + + if (rc < 0) + { + int myerrno = errno; + + fprintf(stderr, "%s Couldn't send go-ahead byte '%02x' to child %p, errno %d" + , time_stamp(), ga_data, chp, myerrno); + errno = myerrno; + perror(" "); + } + + status[0] = ERQ_OK; + replyn(chp->handle, 1, 2, + status, 1, + &chp->ticket, TICKET_SIZE); + return; + } + + free_child(chp); /* Don't need this in the child process */ + reply1(get_handle(mesg), status, 2); +} /* erq_spawn() */ + +/*-------------------------------------------------------------------------*/ +void +erq_kill (char *mesg, int msglen) + +/* ERQ_KILL: Send a signal to one of the children (default is SIGKILL). + * If applied to a socket, the socket is closed. + */ + +{ + ticket_t *ticket; + child_t *chp; + socket_t *sp; + int sig; + char status; + + /* Check the message */ + switch(msglen-TICKET_SIZE) + { + case 9: + sig = SIGKILL; + break; + case 13: + sig = read_32(mesg+9+TICKET_SIZE); + break; + default: + bad_request(mesg); + return; + } + + ticket = (struct ticket_s *) (mesg+9); + + /* Find the command child by the ticket */ + for (chp = childs; chp; chp = chp->next) + if (!memcmp(ticket, &chp->ticket, TICKET_SIZE)) + break; + + if (chp) + { + /* Found it - send the signal */ + XPRINTF((stderr, "%s Kill child %p (pid %d) with signal %d\n" + , time_stamp(), chp, chp->pid, sig)); + if (sig >= 0) + sig = kill(chp->pid, sig); + status = sig < 0 ? ERQ_E_ILLEGAL : ERQ_OK; + reply1(get_handle(mesg), &status, 1); + return; + } + + /* Maybe its a socket? */ + for (sp = sockets; sp; sp = sp->next) + if (!memcmp(ticket, &sp->ticket, TICKET_SIZE)) + break; + + if (sp) + { + /* Yup: close it */ + XPRINTF((stderr, "%s Close socket %p", time_stamp(), sp)); + close_socket(sp); + status = ERQ_OK; + reply1(get_handle(mesg), &status, 1); + return; + } + + status = ERQ_E_TICKET; + reply1(get_handle(mesg), &status, 1); +} /* erq_kill() */ + +/***************************************************************************/ + diff --git a/src/util/xerq/lookup.c b/src/util/xerq/lookup.c new file mode 100644 index 0000000..8c9e0ca --- /dev/null +++ b/src/util/xerq/lookup.c @@ -0,0 +1,193 @@ +/*--------------------------------------------------------------------------- + * XErq - Address Lookup + * (C) Copyright 1995 by Brian Gerst. + *--------------------------------------------------------------------------- + * Here are the function to lookup up internet addresses and names. + * If the first lookup attempt doesn't succeed, a retry is attempted + * five seconds later. + * + * TODO: The functions block the ERQ. + *--------------------------------------------------------------------------- + */ + +#include "defs.h" + +/*-------------------------------------------------------------------------*/ +void +erq_rlookup(char *mesg, int msglen) + +/* ERQ_RLOOKUP: look up a hostname by an address. + */ + +{ + struct hostent *hp; + int len; + char addr[4]; + + if (msglen != 13) + { + const char status=ERQ_E_ARGLENGTH; + reply1(get_handle(mesg), &status, 1); + return; + } + + memcpy(addr, mesg+9, 4); + + XPRINTF((stderr, "%s rlookup %02x.%02x.%02x.%02x\n" + , time_stamp(), addr[0], addr[1], addr[2], addr[3])); + + hp = gethostbyaddr(addr, 4, AF_INET); + if (!hp && mesg[8] == ERQ_RLOOKUP) + { + mesg[8]++; /* No second retry */ + XPRINTF((stderr, "%s Retry in 5 seconds.\n", time_stamp())); + add_retry(erq_rlookup, mesg, 13, 5); + return; + } + + if (hp) + { + XPRINTF((stderr, "%s rlookup found '%s'\n", time_stamp(), hp->h_name)); + len = strlen(hp->h_name)+1; + } + else + { + XPRINTF((stderr, "%s rlookup failed.\n", time_stamp())); + len = 0; + } + + if (hp) + replyn(get_handle(mesg), 0, 2, + mesg+9, 4, + hp->h_name, len); + else + reply1(get_handle(mesg), mesg+9, 4); +} /* erq_rlookup() */ + +/*-------------------------------------------------------------------------*/ +void +erq_lookup(char *mesg, int len) + +/* ERQ_LOOKUP: look up an address by a hostname. + */ + +{ + struct hostent *hp; + char * msg; + + msg = mesg; + if (mesg[len-1] != 0) + { + /* Create a local copy of the message in which the string + * has a proper termination. + */ + msg = malloc(len+1); + if (!msg) + { + XPRINTF((stderr, "%s Out of memory.\n", time_stamp())); + die(); + } + memcpy(msg, mesg, len); + msg[len] = 0; + len++; + } + + XPRINTF((stderr, "%s lookup '%s'\n", time_stamp(), msg+9)); + hp = gethostbyname(msg+9); + if (!hp && msg[8] == ERQ_LOOKUP && h_errno == TRY_AGAIN) + { + XPRINTF((stderr, "%s Retry in 5 seconds.\n", time_stamp())); + mesg[8]++; /* No second retry */ + add_retry(erq_lookup, msg, len, 5); + if (msg != mesg) + free(msg); + return; + } + + { + char r_ok[] = { ERQ_OK }; + char r_notfound[] = { ERQ_E_NOTFOUND }; + char r_noaddr[] = { 0, 0, 0, 0 }; + + if (hp) + XPRINTF((stderr, "%s lookup found %02x.%02x.%02x.%02x\n" + , time_stamp(), hp->h_addr[0], hp->h_addr[1] + , hp->h_addr[2], hp->h_addr[3])); + else + XPRINTF((stderr, "%s lookup failed.\n", time_stamp())); + replyn(get_handle(mesg), 0, 3, + hp ? r_ok : r_notfound, 1, + hp ? (char *) hp->h_addr : r_noaddr, 4, + msg+9, len-9); + } + + if (msg != mesg) + free(msg); +} /* erq_lookup() */ + +/*-------------------------------------------------------------------------*/ +#ifdef USE_IPV6 + +void +erq_rlookupv6(char *mesg, int msglen) + +/* ERQ_RLOOKUPV6: look up an IPv6 address by a hostname. + */ + +{ + int i; + char *mbuff, *buf; + size_t buflen; + struct addrinfo req, *ai, *ai2; + static char *msg_invalid = "invalid-format"; + static char *msg_nomem = "out-of-memory"; + + buflen = msglen -9 +1; + buf = malloc(msglen -9 +1); + if (!buf) + { + reply1(get_handle(mesg), msg_nomem, strlen(msg_nomem)+1); + return; + } + + memcpy(buf, mesg+9, msglen-9); + buf[buflen-1] = '\0'; + + memset(&req, 0, sizeof(struct addrinfo)); + req.ai_family = AF_INET6; + req.ai_flags = AI_CANONNAME; + i = getaddrinfo(buf, NULL, &req, &ai); + if (!i) + for (ai2 = ai + ; ai2 && (ai2->ai_family != AF_INET) + && (ai2->ai_family != AF_INET6) + ; ai2 = ai2->ai_next) NOOP; + + if (!i && ai2 && ai2->ai_canonname) + { + mbuff = malloc(strlen(ai2->ai_canonname)+1+buflen); + if (!mbuff) + { + free(buf); + reply1(get_handle(mesg), msg_nomem, strlen(msg_nomem)+1); + return; + } + strcpy(mbuff, buf); + strcat(mbuff, " "); + strcat(mbuff, ai2->ai_canonname); + reply1(get_handle(mesg), mbuff, strlen(mbuff)+1); + free(mbuff); + } + else + reply1(get_handle(mesg), msg_invalid, strlen(msg_invalid)+1); + + if (!i) + freeaddrinfo(ai); + + free(buf); +} /* erq_rlookupv6() */ + +#endif /* USE_IPV6 */ + +/***************************************************************************/ + diff --git a/src/util/xerq/lpc/README b/src/util/xerq/lpc/README new file mode 100644 index 0000000..32fb030 --- /dev/null +++ b/src/util/xerq/lpc/README @@ -0,0 +1,5 @@ +Here are some example lpc files using the socket capabilities of tw-erq. + +The socketd is an easy interface from lpc to the erq. I will write some +docs sometime soon, but the examples here should be fairly easy to +understand. diff --git a/src/util/xerq/lpc/TODO b/src/util/xerq/lpc/TODO new file mode 100644 index 0000000..5713665 --- /dev/null +++ b/src/util/xerq/lpc/TODO @@ -0,0 +1,2 @@ +Write some docs +Add mud mode sockets similar to the Mudos variety (?) diff --git a/src/util/xerq/lpc/_ifinger.c b/src/util/xerq/lpc/_ifinger.c new file mode 100644 index 0000000..43b0da9 --- /dev/null +++ b/src/util/xerq/lpc/_ifinger.c @@ -0,0 +1,100 @@ +#include "socket.h" +#include + +#define LUSER 0 +#define RUSER 1 +#define HOST 2 +#define CONTINUED 3 + +mapping sockets; + +void callback(int fd, int act, mixed a, mixed b); + +status main(string str) +{ + string user, host; + int sock; + if (!sockets) sockets = allocate_mapping(0, 4); + if (!adminp(this_player())) return 0; + if (!str) str=""; + host = __HOST_NAME__; + user = str; + sscanf(str, "%s@%s", user, host); + + sock = SOCKETD->socket_connect(host, 79, #'callback); + sockets[sock, LUSER] = this_player(); + sockets[sock, RUSER] = user; + sockets[sock, HOST] = host; + printf("[finger to: %s@%s]\n", user, host); + call_out("time_out", 90, sock); + return 1; +} + +void callback(int sock, int act, mixed a, mixed b) +{ + if (!sockets[sock, LUSER] && act != SOCKET_CLOSE) { + SOCKETD->socket_close(sock); + return; + } + switch(act) { + case SOCKET_READY: + SOCKETD->socket_write(sock, sprintf("%s\r\n", sockets[sock, RUSER])); + break; + case SOCKET_READ: + if (!sockets[sock, CONTINUED]) { + tell_object(sockets[sock, LUSER], sprintf("[%s@%s]\n", + sockets[sock, RUSER], + sockets[sock, HOST])); + sockets[sock, CONTINUED] = 1; + } + tell_object(sockets[sock, LUSER], a); + break; + case SOCKET_CLOSE: + m_delete(sockets, sock); + break; + case SOCKET_ERROR: { + string err; + switch(a) { + case ECONNREFUSED: + err = "Connection Refused"; + break; + case EHOSTUNREACH: + err = "Host Unreachable"; + break; + case ENETUNREACH: + err = "Net Unreachable"; + break; + default: + err = sprintf("Code %d", a); + break; + } + tell_object(sockets[sock, LUSER], + sprintf("ifinger: Error in connection to %s: %s.\n", + sockets[sock, HOST], + err)); + m_delete(sockets, sock); + } + break; + } + return; +} + +void help() +{ + write("Usage: ifinger [[]@]\n" + "Send an internet finger request.\n"); + return; +} + +void time_out(int sock) +{ + if (sockets[sock, LUSER]) + tell_object(sockets[sock, LUSER], + sprintf("Finger to %s@%s timed out.\n", + sockets[sock, RUSER], + sockets[sock, HOST])); + m_delete(sockets, sock); + return; +} + +mapping query_sockets() { return copy_mapping(sockets); } diff --git a/src/util/xerq/lpc/_telnet.c b/src/util/xerq/lpc/_telnet.c new file mode 100644 index 0000000..870de5a --- /dev/null +++ b/src/util/xerq/lpc/_telnet.c @@ -0,0 +1,47 @@ +#define TELNET_OB "secure/sockets/telnet_ob" + +mapping sessions = ([ ]); + +status main(string str) { + string host; + int port; + if (!adminp(this_player())) + return 0; + if (!str) { + if (sessions[this_player()] == 0) + return + notify_fail("telnet: Could not find detatched session.\n"); + (void)sessions[this_player()]->reattach(); + return 1; + } + if (str == "-q") { + if (sessions[this_player()] == 0) + return + notify_fail("telnet: Could not find session.\n"); + destruct(sessions[this_player()]); + return 1; + } + if (sessions[this_player()]) + return + notify_fail("telnet: You have a detatched session.\n" + "Type 'telnet' to reattach to it.\n"); + if (sscanf(str, "%s %d", host, port) != 2) + host = str, port = 23; + sessions[this_player()] = clone_object(TELNET_OB); + (void)sessions[this_player()]->start(host, port); + return 1; + } + +void help() { + write("telnet [
[] | -q]\n" + "Telnet to the address given, or reactivate a dormant session.\n" + "You may only have one session at any given time.\n" + "Several telnet commands are available, a telnet\n" + "command starts with the escape character (^[).\n" + "Use \"^[?\" to get a list of available telnet commands.\n" + "The \"-q\" option allows you to close a telnet session\n" + "from the commandline.\n"); + return; + } + +mapping query_sessions() { return copy_mapping(sessions); } diff --git a/src/util/xerq/lpc/httpd.c b/src/util/xerq/lpc/httpd.c new file mode 100644 index 0000000..351b182 --- /dev/null +++ b/src/util/xerq/lpc/httpd.c @@ -0,0 +1,89 @@ +#include "socket.h" + +#if 0 +#define debug(x) if (find_player("garion")) \ + tell_object(find_player("garion"), (x)) +#else +#define debug(x) +#endif + +#define WWW_PATH "secure/sockets/www" +#define ERROR "Error\n" + +int sock; + +static string parse_request(string file); +static void listen_call(int fd, int act, mixed a, mixed b); +static void callback(int fd, int act, mixed a, mixed b); + +void reset(int arg) +{ + if (arg) return; + sock=SOCKETD->socket_listen(5152, #'listen_call); + debug("httpd started.\n"); +} + +static void listen_call(int fd, int act, mixed a, mixed b) +{ + debug(sprintf("listen_call(%d,%d,%O,%O)\n",fd,act,a,b)); + switch(act) { + case SOCKET_READY: + return; + case SOCKET_ACCEPT: + SOCKETD->socket_accept(fd, #'callback); + return; + case SOCKET_ERROR: + sock=-1; + case SOCKET_CLOSE: + destruct(this_object()); + return; + } +} + +static void callback(int fd, int act, mixed a, mixed b) +{ + debug(sprintf("callback(%d,%d,%O,%O)\n",fd,act,a,b)); + switch(act) { + case SOCKET_READ: { + string file, *tmp; + tmp=explode(a, "\r\n"); + tmp=explode(tmp[0], " "); + if (tmp[0]!="GET") { + SOCKETD->socket_close(fd); + return; + } + file=tmp[1]; + a=parse_request(file); + SOCKETD->socket_write(fd, a); + SOCKETD->socket_close(fd); + return; + } + case SOCKET_ERROR: { + SOCKETD->socket_close(fd); + } + } +} + +static string parse_request(string file) +{ + string data, tmp, *args; + + args=explode(file, "/")-({""}); + if (!sizeof(args)) return ERROR; + + file=sprintf("%s/%s.c", WWW_PATH, args[0]); + + if (file_size(file) > 0) { + if (tmp=catch(data=call_other(file, "www_main", args[1..]))) { + return ERROR; + } + return data; + } + return ERROR; +} + +void destructor() +{ + if (sock<0) return; + SOCKETD->socket_close(sock); +} diff --git a/src/util/xerq/lpc/socket.h b/src/util/xerq/lpc/socket.h new file mode 100644 index 0000000..813fb26 --- /dev/null +++ b/src/util/xerq/lpc/socket.h @@ -0,0 +1,130 @@ +// +// Wunderland Mudlib +// +// sys/daemon/socket.h -- Makros fuer Socketd +// +// $Log: socket.h,v $ +// Revision 1.8 2002/10/22 11:39:00 Fiona +// State info S_WAITS and improved blocking handling +// + +#ifndef __SOCKET_H__ +#define __SOCKET_H__ + +#define SOCKETD "/global/daemon/socketd" +#define SOCKETLOG "SOCKETD" + +// whos allowed to do critical things? +#define SPECIAL_PREVILEGE IS_ARCH(this_interactive()) +#define VALID_SOCKETS ({ "/secure/", "/global/" }) + +// give usefull output, eg: sprintf("%O", x) +#ifndef MIXED2STR +# define MIXED2STR(x) mixed_to_string(x) +#endif + +// raise an error where the guilty part is our caller +#ifndef RAISE_ERROR +# define RAISE_ERROR(x) raise_error("@"+(x)); +#endif + +#define MAX_SOCKETS 15 + +// callback actions +#define SOCKET_ACCEPT 0 +#define SOCKET_READ 1 +#define SOCKET_CLOSE 2 +#define SOCKET_ERROR 3 +#define SOCKET_READY 4 +#define SOCKET_WRITTEN 5 +#define SOCKET_INCOMPLETE 6 +#define SOCKET_NOPEND 7 + +// access to the sockets mapping +#define S_SOCKOBJ 0 +#define S_TYPE 1 +#define S_TICKET 2 +#define S_STATE 3 +#define S_OPTS 4 +#define S_HOST 5 +#define S_PORT 6 +#define S_LISTEN_FD 6 // for TCP_ACCEPT only +#define S_LPORT 7 +#define S_CALLBACK 8 +#define S_OBJECT 9 +#define S_PENDING 10 // just for written-before-connected +#define S_OWNER 11 +#define S_TO_WRITE 12 +#define S_WRITTEN 13 +#define S_RECEIVED 14 +#define S_WAITS 15 +#define S_WAIT_DATA 16 + +// values of S_TYPE +// bit 0: open/listen +// bit 1: tcp/udp +// bit 2: accepter (intern) +#define TCP_OPEN 0 +#define TCP_LISTEN 1 +#define UDP 3 +#define TCP_ACCEPT 5 + +// values of S_STATE +#define S_UNCONNECTED 0 +#define S_CONNECTED 1 +#define S_LISTEN 2 +#define S_UDP 3 +#define S_CLOSING 4 + +// values of S_OPTS (bits) +#define SOCKET_ASCII 0 +#define SOCKET_BINARY 1 +#define SOCKET_MUDMODE 2 + +// values of S_WAITS +#define S_WAITS_NOT 0 +#define S_WAITS_ERQ 1 +#define S_WAITS_INCOM 2 +#define S_WAITS_BLOCK 3 + +// should be defined by the driver according to the xerq +// configure option --with-erq-max-send=VALUE (default = 1024) +#ifndef __ERQ_MAX_SEND__ +# define __ERQ_MAX_SEND__ 256 // for old driver/xerq combinations +#endif + +// same as above, --with-erq-max-reply=VALUE (default = 1024) +#ifndef __ERQ_MAX_REPLY__ +# define __ERQ_MAX_REPLY__ 1024 +#endif + +#define WRITE_MAX (__ERQ_MAX_SEND__ - 9) + +// get clone number +#define UNIQUE_ID(x) (to_int(object_name(x)[strlen(SOCKETD)+1..])) + +#ifdef NEED_PROTOTYPES +#ifndef __SOCKET_H_PROTO__ +#define __SOCKET_H_PROTO__ + +// prototypes of daemon functions +object ___debug(int on); +static void accept_cb(int* msg, int ufd); +static void callback(int ufd, int action, mixed args); +static void debug(varargs mixed* x); +static void flush(int fd); +static void looked_up(int* msg, int ufd); +static void lookup(string host, closure cb); +static mixed* note_err(string str, int* msg, int fd); +int remove(); +static void sendbuf(int ufd, int* data, int off); +static void socket_cb(int* msg, int ufd); +int socket_close(int fd); +static string to_ascii(int* msg); +static string to_mudmode(mixed data); +static int valid_socket(object ob); + +#endif // __SOCKET_H_PROTO__ +#endif // NEED_PROTOTYPES + +#endif // __SOCKET_H__ diff --git a/src/util/xerq/lpc/socketd.c b/src/util/xerq/lpc/socketd.c new file mode 100644 index 0000000..b74b061 --- /dev/null +++ b/src/util/xerq/lpc/socketd.c @@ -0,0 +1,1196 @@ +// +// Wunderland Mudlib +// +// global/daemon/socketd.c -- internet-sockets (needs xerq) +// +// This file comes in two guises - the blueprint is the master +// actual managing all data transfers and the clones representin +// the connections for the using wizards. They get the socket object +// from the master and handle all subsequent issues with object. +// +// Far based on socketd from Brian Gerst (Garion@Timewarp) +// Inspired by the Msg modul from Sriram Srinivasan +// Mudmode conversion based on code from Skylight (pli@shell.portal.com) +// +// Find the newest version of this file at +// http://wl.mud.de/mud/doc/wwwstd/standardobjekte.html +// +// $Log: socketd.c,v $ +// Revision 1.15 2004/11/10 07:25:06 Fiona +// Fixed warning problem with 3.3 in State() (Joseph Graham, Lars Duening) +// + +/***** + * + * How does the socketd work internally? + * + * Each connection has an associated socket object which handles all + * communication with the wizards object. These objects stay in the + * inventory of the socketd. + * + * To destringuish the different connections when a messages comes + * in from the erq the clone number of the socket object is used. + * The number is closured with the callback function. The number + * is used instead of the object itself because the object may be + * destructed meanwhile: the connection is to be killed then but the + * ticket is needed for that. So we need some unique identifier that + * is still usable after the object's destruction. + * + * All opened connections are stored in sockets with the unique identifier + * (the clone number of the socket object) as key. Furthermore there is + * used_fd which translates unique identifieres to file descriptor numbers + * which are used outside the socketd to identify a connection. The fds + * are numbered from 0 to n using old numbers if that fd is not active + * anymore. + * + * If Write() or Send() is issued on a connection that is not open yet + * the data will be buffered and sent when the socket becomes writabe. + * It is even possible to Close() the socket wich will be delayed until + * all buffered data is sent. Bear in mind that a Close() will not destruct + * the socket object in that case and you will get the callbacks if the + * issuing object still exists. If it does not exist anymore you cannot + * tell if the data is really sent or some timeout occured. So in general + * you should wait with Send()s until the connection is established. + * + */ + +#pragma strict_types +#pragma no_inherit +#pragma no_shadow + +#include <wizlevels.h> +#include <erq.h> + +#define NEED_PROTOTYPES +#include <daemon/socket.h> + +#ifdef ME +#undef ME +#endif +#define ME this_object() +#ifdef PO +#undef PO +#endif +#define PO previous_object() + +// Access for internal output cache +#define OUT_UFD 0 // destination FD +#define OUT_DATA 1 // the data itself +#define OUT_SIZE 2 // size of all previous chunks of this Write() + +mapping sockets; // all the open sockets +mixed* output; // things to be sent +int sending; // answer from erq pending +mapping used_fd; // the 'file descriptor' translation +int so_fd; // fd of socket object +int so_ufd; // socket object's clone number +string so_buf; // mudmode buffer +mixed so_bufs; // expected packet size +int sent, rcvt; // number of sent and received bytes +object debugger; +private string* valids; + +void create() { + // _debug(1); + if (clonep()) { + if (!PO || object_name(PO) != SOCKETD) { + destruct(ME); + return; + } + move_object(ME, PO); + so_fd = -1; + return; + } + seteuid(getuid()); + if (!sockets) sockets = m_allocate(0, 17); + if (!used_fd) used_fd = ([]); + if (!output) output = ({}); + debug("*** created socket daemon"); +} + +////// +// functions used in the socket objects only + +// socket object is initialized from the daemon here +object so_init(mapping socks, mapping usedfd, int fd) { + if (!clonep()) return 0; + if (object_name(PO) != SOCKETD) return 0; + if (sockets) return ME; + sockets = socks; // local reference to global mapping + used_fd = usedfd; // dito + so_fd = fd; + so_ufd = UNIQUE_ID(ME); + return ME; +} + +// some checks for the user functions in the socket objects +static int so_check(string fun) { + if (!clonep()) return 0; + if (so_fd < 0 || !member(sockets, so_fd)) { + remove(); + RAISE_ERROR("uninitialized socket object\n"); + } + if (!member(used_fd, so_ufd) || used_fd[so_ufd] != so_fd) { + remove(); + RAISE_ERROR("filehandle mismatch\n"); + } + if (!sockets[so_fd, S_OBJECT]) { + remove(); + return 0; + } + if (PO != sockets[so_fd, S_OBJECT]) + RAISE_ERROR("privilege violation: "+fun+"()\n"); + return 1; +} + +// write data over the socket (tcp only) (user function) +public int Write(mixed data) { + int size; + if (!so_check("Write")) return 0; + if (sockets[so_fd, S_OPTS] & SOCKET_MUDMODE) { + data = to_mudmode(data); + data = to_array(data)[0..strlen(data)-1]; + size = sizeof(data); + data = ({ (size & 0x7f000000) >> 24, (size & 0xff0000) >> 16, + (size & 0xff00) >> 8, size & 0xff }) + data; + } else { + if (!stringp(data) && !pointerp(data)) + RAISE_ERROR("Bad argument 1 to Write()\n"); + } + + return (int) SOCKETD->socket_write(so_ufd, data, 0); +} + +// send data over the socket (udp only) (user function) +public int Send(string host, int port, mixed msg) { + if (!so_check("Send")) return 0; + if (!stringp(host)) RAISE_ERROR("Bad argument 1 to Send()\n"); + if (!intp(port)) RAISE_ERROR("Bad argument 2 to Send()\n"); + if (!stringp(msg) && !pointerp(msg)) + RAISE_ERROR("Bad argument 3 to Send()\n"); + if (sockets[so_fd, S_STATE] != S_UDP) + RAISE_ERROR("Send() on a non-udp socket\n"); + + return (int) SOCKETD->udp_write(so_ufd, host, port, msg); +} + +// accepts a new connection (tcp_listen only) (user function) +public object Accept(closure cb) { + object ob; + if (!so_check("Accept")) return 0; + if (sockets[so_fd, S_TYPE] != TCP_LISTEN) + RAISE_ERROR("Accept() called on non-listening socket\n"); + if (!closurep(cb) || !(ob=to_object(cb))) + RAISE_ERROR("Bad argument 1 to Accept()\n"); + + return (object) SOCKETD->socket_accept(so_ufd, cb); +} + +// close the opened socket (user function) +public int Close() { + int i; + if (!so_check("Close")) return 0; + return (int) SOCKETD->socket_close(so_ufd); +} + +// get all connection information on this socket (user function) +public mixed* State() { + mixed* data; + if (!so_check("State")) return 0; + map(sockets, (: if ($1 == $3) $4 = copy($2); return 0; :), so_fd, &data); + data[S_TICKET] = copy(data[S_TICKET]); + data[S_WAIT_DATA] = 0; // not visible for user + return data; +} + +////// +// functions used in the daemon only + +// create a new socket (user function) +public object New(int type, mixed host, int port, closure cb, int opts) { + int fd, *fds, ufd; + object cb_o, so; + + debug("sockD::New(%O, %O, %O, %O, %O)", type, host, port, cb, opts); + + // TCP_ACCEPT could be generated internally only + if (!intp(type) || type < 0 || type > (extern_call() ? 3 : 5)) + RAISE_ERROR("Bad argument 1 to New()\n"); + if (!(type & 4)) { + if ((type & 1 && host) || (!(type & 1) && !stringp(host))) + RAISE_ERROR("Bad argument 2 to New()\n"); + } else if (!objectp(host)) + RAISE_ERROR("Bad argument 2 to New()\n"); + if (!intp(port)) + RAISE_ERROR("Bad argument 3 to New()\n"); + if (!(type & 4) && (!closurep(cb) || !(cb_o=to_object(cb)))) + RAISE_ERROR("Bad argument 4 to New()\n"); + if (!intp(opts)) + RAISE_ERROR("Bad argument 5 to New()\n"); + + if (extern_call() && !valid_socket(cb_o)) + RAISE_ERROR("privilege violation: New()\n"); + + if (opts & SOCKET_MUDMODE) { + opts |= SOCKET_BINARY; + if (type == UDP) RAISE_ERROR("mudmode is tcp only\n"); + } + + // find empty fd + fds = m_values(used_fd); + for (fd = 0; fd < MAX_SOCKETS; fd++) { + if (member(fds, fd) < 0) break; + } + if (fd >= MAX_SOCKETS) return 0; // no slot available + + if (type & 4) cb_o = sockets[port, S_OBJECT]; + + while (1) { + so = (object) clone_object(program_name())->so_init(sockets, used_fd, fd); + ufd = UNIQUE_ID(so); + if (!member(used_fd, ufd)) break; + // could happen but is very unlikely, just try again + destruct(so); + } + + used_fd[ufd] = fd; + sockets[fd, S_SOCKOBJ] = so; + sockets[fd, S_TYPE] = type; + sockets[fd, S_TICKET] = 0; + sockets[fd, S_STATE] = S_UNCONNECTED; + sockets[fd, S_OPTS] = opts; + sockets[fd, S_HOST] = host; + sockets[fd, S_PORT] = port; + sockets[fd, S_CALLBACK] = cb; + sockets[fd, S_OBJECT] = cb_o; + sockets[fd, S_PENDING] = 0; + sockets[fd, S_OWNER] = getuid(cb_o); + + if (type & 1) + sockets[fd, S_LPORT] = port; + if (type & 4) + sockets[fd, S_LPORT] = sockets[sockets[fd, S_LISTEN_FD], S_PORT]; + + switch (type) { + case TCP_OPEN: + lookup(host, lambda(({ 'msg }), ({ #'looked_up, 'msg, ufd }))); + break; + + case TCP_LISTEN: + send_erq(ERQ_LISTEN, ({ port/256, port&255 }), + lambda(({ 'msg }), ({ #'socket_cb, 'msg, ufd }))); + break; + + case UDP: + send_erq(ERQ_OPEN_UDP, ({ port/256, port&255 }), + lambda(({ 'msg }), ({ #'socket_cb, 'msg, ufd }))); + } + + return so; +} + +// write data over a socket +int socket_write(int ufd, mixed msg, int* udp_addr) { + int size, chunk, *ticket, *out, pos, is_udp, fd; + string snipsel; + mixed* data; + + debug("sockD::socket_write(%O, %O)", ufd, udp_addr); + //debug("sockD::socket_write(%O, %O, %O)", ufd, msg, udp_addr); + + if (!intp(ufd)) RAISE_ERROR("Bad argument 1 to socket_write()\n"); + if (PO && PO != ME) { + if (!m_contains(&fd, used_fd, ufd) || PO != sockets[fd, S_SOCKOBJ]) + RAISE_ERROR("privilege violation: socket_write()\n"); + } else { + if (!m_contains(&fd, used_fd, ufd)) return 0; //vanished + } + if (!stringp(msg) && !pointerp(msg)) + RAISE_ERROR("Bad argument 2 to socket_write()\n"); + is_udp = sockets[fd, S_STATE] == S_UDP; + if (is_udp && !pointerp(udp_addr) || !is_udp && udp_addr) + RAISE_ERROR("Bad argument 3 to socket_write()\n"); + if ((!udp_addr && sockets[fd, S_STATE] != S_CONNECTED) + || !sockets[fd, S_TICKET]) { + if (sockets[fd, S_STATE] == S_UNCONNECTED) { + data = sockets[fd, S_PENDING]; + if (!data) data = ({}); + data += ({ ({ msg, udp_addr }) }); + return 2; + } + else + RAISE_ERROR("socket_write() on an unconnected socket\n"); + } + + if (!udp_addr) udp_addr = ({}); + ticket = sockets[fd, S_TICKET]; + chunk = WRITE_MAX - sizeof(ticket) - sizeof(udp_addr); + + if (pointerp(msg)) { + size = sizeof(msg); + for (; pos < size; pos += chunk) { + sendbuf(ufd, udp_addr + msg[pos .. pos+chunk-1], pos); + ++sockets[fd, S_TO_WRITE]; + } + + } else { + size = strlen(msg); + for (; pos < size; pos += chunk) { + snipsel = msg[pos .. pos+chunk-1]; + sendbuf(ufd, udp_addr + to_array(snipsel)[0..strlen(snipsel)-1], pos); + ++sockets[fd, S_TO_WRITE]; + } + } + if (!sockets[fd, S_WAITS]) flush(ufd); + + return 1; +} + +// accepts a pending connection from a listened to port +object socket_accept(int ufd, closure cb) { + object so, ob; + int fd; + + debug("sockD::socket_accept(%O, %O)", ufd, cb); + if (!intp(ufd)) RAISE_ERROR("Bad argument 1 to socket_accept()\n"); + if (!m_contains(&fd, used_fd, ufd) || PO != sockets[fd, S_SOCKOBJ]) + RAISE_ERROR("privilege violation: socket_accept()\n"); + if (sockets[fd, S_TYPE] != TCP_LISTEN) + RAISE_ERROR("socket_accept() called on non-listening socket\n"); + if (!closurep(cb) || !(ob=to_object(cb))) + RAISE_ERROR("Bad argument 2 to socket_accept()\n"); + + so = New(TCP_ACCEPT, sockets[fd, S_SOCKOBJ], fd, cb, sockets[fd, S_OPTS]); + if (!so) { // no more sockets left + debug("too many connections, closing accepted connection"); + return 0; + } + + send_erq(ERQ_ACCEPT, sockets[fd, S_TICKET], + lambda(({ 'msg }), ({ #'accept_cb, 'msg, UNIQUE_ID(so) }))); + + return so; +} + +// write data via udp +int udp_write(int ufd, string host, int port, mixed umsg) { + int fd; + debug("sockD::udp_write(%O, %O)", ufd, host, port, umsg); + if (!intp(ufd)) RAISE_ERROR("Bad argument 1 to udp_write()\n"); + if (!m_contains(&fd, used_fd, ufd) || PO != sockets[fd, S_SOCKOBJ]) + RAISE_ERROR("privilege violation: udp_write()\n"); + if (!stringp(host)) RAISE_ERROR("Bad argument 2 to udp_write()\n"); + if (!intp(port)) RAISE_ERROR("Bad argument 3 to udp_write()\n"); + if (!stringp(umsg) && !pointerp(umsg)) + RAISE_ERROR("Bad argument 4 to udp_write()\n"); + if (sockets[fd, S_TYPE] != UDP) + RAISE_ERROR("udp_write() on a non-udp socket\n"); + + lookup(host, lambda(({ 'msg }), + ({ #'socket_write, ufd, umsg, + ({ #'+, ({ #'[..], 'msg, 1, 4 }), + ({ #'({, port / 256, port & 255 }) + }) + }) )); + return 1; +} + +// a socket is closed here. it can only be done from the socket object +int socket_close(int ufd) { + int i, fd, fd2, ufd2; + object so; + + debug("sockD::socket_close(%O)", ufd); + if (!intp(ufd)) RAISE_ERROR("Bad argument 1 to socket_close()\n"); + if (PO && PO != ME) { + if (!m_contains(&fd, used_fd, ufd) || PO != sockets[fd, S_SOCKOBJ]) + RAISE_ERROR("privilege violation: socket_close()\n"); + } else { + if (!m_contains(&fd, used_fd, ufd)) return 0; //vanished + } + if (!member(sockets, fd)) return 0; + + // delete associated data + i = sizeof(output); + for (; i--;) + if (output[i][OUT_UFD] == ufd) + output[i..i] = ({}); + + if (sockets[fd, S_TICKET] && sockets[fd, S_STATE] != S_CLOSING) { + // never kill twice + sockets[fd, S_STATE] = S_CLOSING; + send_erq(ERQ_KILL, sockets[fd, S_TICKET] + ({ 0, 0, 0, 0 }), + lambda(({ 'msg }), ({ #'socket_cb, 'msg, ufd }))); + } + else { + so = sockets[fd, S_SOCKOBJ]; + m_delete(sockets, fd); + m_delete(used_fd, ufd); + if (so) destruct(so); + } + return 1; +} + +// looks up a DNS name +static void lookup(string host, closure cb) { + int *msg; + + debug("sockD::lookup(%O, %O)", host, cb); + msg = allocate(5); + if (sscanf(host, "%d.%d.%d.%d", msg[1], msg[2], msg[3], msg[4]) == 4) { + funcall(cb, msg); + return; + } + + send_erq(ERQ_LOOKUP, host, cb); +} + +// the DNS answer for TCP is processed here +static void looked_up(int* msg, int ufd) { + int fd; + + debug("sockD::looked_up(%O, %O)", msg, ufd); + if (!m_contains(&fd, used_fd, ufd)) return; // vanished + + if (msg[0] != ERQ_OK) { + callback(ufd, SOCKET_ERROR, note_err("unknown response", msg, fd)); + return; + } + + sockets[fd, S_HOST] = sprintf("%d.%d.%d.%d", + msg[1] & 255, msg[2] & 255, msg[3] & 255, msg[4] & 255); + + send_erq(ERQ_OPEN_TCP, msg[1..4] + + ({ sockets[fd, S_PORT] / 256, sockets[fd, S_PORT] & 255 }), + lambda(({ 'mess }), ({ #'socket_cb, 'mess, ufd }))); +} + +// most of data gets here from the erq (see write_cb) +static void socket_cb(int* msg, int ufd) { + int state, opts, port, type, fd; + string host; + object so; + + debug("sockD::socket_cb(%O, %O)", msg, ufd); + if (!m_contains(&fd, used_fd, ufd)) return; // should not happen + msg = map(msg, #'&, 255); + type = sockets[fd, S_TYPE]; + state = sockets[fd, S_STATE]; + opts = sockets[fd, S_OPTS]; + + switch (msg[0]) { + + case ERQ_OK: { + debug("ERQ_OK"); + if (!sockets[fd, S_TICKET]) { + switch (type) { + case TCP_OPEN: state = S_CONNECTED; break; + case TCP_LISTEN: state = S_LISTEN; break; + case UDP: state = S_UDP; break; + default: debug("unexpected type", type); break; + + case TCP_ACCEPT: + debug("accepting"); + host = sprintf("%d.%d.%d.%d", msg[1], msg[2], msg[3], msg[4]); + port = msg[5] * 256 + msg[6]; + if (member(sockets, sockets[fd, S_LISTEN_FD])) + sockets[sockets[fd, S_LISTEN_FD], S_PENDING] = 0; + sockets[fd, S_TICKET] = msg[7..]; + sockets[fd, S_STATE] = S_CONNECTED; + sockets[fd, S_HOST] = host; + sockets[fd, S_PORT] = port; + callback(ufd, SOCKET_READY, + ({ sockets[fd, S_SOCKOBJ], host, port })); + return; + } + sockets[fd, S_TICKET] = msg[1..]; + sockets[fd, S_STATE] = state; + callback(ufd, SOCKET_READY, 0); + } + else { + debug("socket has a ticket"); + } + return; + } + + case ERQ_STDOUT: { + debug("ERQ_STDOUT"); + switch (state) { + + case S_LISTEN: + debug("incoming connection (tcp)"); + if (sockets[fd, S_SOCKOBJ] && sockets[fd, S_OBJECT]) { + sockets[fd, S_PENDING] = 1; + callback(ufd, SOCKET_ACCEPT, 0); + } + else socket_close(ufd); // weird + break; + + case S_CONNECTED: + msg = msg[1..]; + rcvt += sizeof(msg); + ++sockets[fd, S_RECEIVED]; + if (opts & SOCKET_BINARY) + callback(ufd, SOCKET_READ, quote(msg)); + else + callback(ufd, SOCKET_READ, to_ascii(msg)); + break; + + case S_UDP: + debug("incoming connection (udp)"); + host = sprintf("%d.%d.%d.%d", msg[1], msg[2], msg[3], msg[4]); + port = msg[5] * 256 + msg[6]; + msg = msg[7..]; + rcvt += sizeof(msg); + if (opts & SOCKET_BINARY) + callback(ufd, SOCKET_READ, ({ msg, host, port })); + else + callback(ufd, SOCKET_READ, ({ to_ascii(msg), host, port })); + break; + + default: + debug("unexpected state", state); + break; + } + return; + } + + case ERQ_EXITED: + debug("ERQ_EXITED"); + so = sockets[fd, S_SOCKOBJ]; + sockets[fd, S_STATE] = S_CLOSING; + callback(ufd, SOCKET_CLOSE, 0); + m_delete(sockets, fd); + m_delete(used_fd, ufd); + if (so) destruct(so); + return; + + case ERQ_E_ARGLENGTH: + // last message ignored by xerq + callback(ufd, SOCKET_ERROR, note_err("ERQ_E_ARGLENGTH", msg, fd)); + return; + + case ERQ_E_NSLOTS: + callback(ufd, SOCKET_ERROR, note_err("ERQ_E_NSLOTS", msg, fd)); + break; + + case ERQ_E_WOULDBLOCK: + callback(ufd, SOCKET_ERROR, note_err("ERQ_WOULDBLOCK", msg, fd)); + debug("ERQ_E_WOULDBLOCK socket cb"); + break; + + case ERQ_E_TICKET: + callback(ufd, SOCKET_ERROR, note_err("ERQ_E_TICKET", msg, fd)); + break; + + case ERQ_E_ILLEGAL: + callback(ufd, SOCKET_ERROR, note_err("ERQ_E_ILLEGAL", msg, fd)); + break; + + case ERQ_E_UNKNOWN: + callback(ufd, SOCKET_ERROR, note_err("ERQ_E_UNKNOWN", msg, fd)); + break; + + default: + callback(ufd, SOCKET_ERROR, note_err("unknown response", msg, fd)); + break; + } + + // if we get here an error occured. the erq closed the socket already + if (member(sockets, fd)) sockets[fd, S_STATE] = S_CLOSING; + callback(ufd, SOCKET_CLOSE, 0); + socket_close(ufd); +} + +// answers from the erq upon writes get here to handle the +// data buffer (output) according to its answers +static void write_cb(int* msg, int ufd, int offset) { + int fd, x; + sending = 0; + debug("sockD::write_cb(%O, %O)", msg, ufd); + if (!m_contains(&fd, used_fd, ufd)) return; // vanished + + switch (msg[0]) { + + case ERQ_E_INCOMPLETE: + debug("ERQ_E_INCOMPLETE"); + sockets[fd, S_WAITS] = S_WAITS_INCOM; + msg = map(msg, #'&, 255); + x = (((msg[1] << 8) + msg[2] << 8) + msg[3] << 8) + msg[4]; + callback(ufd, SOCKET_INCOMPLETE, ({ x, offset + x }) ); + return; + + case ERQ_OK: + debug("ERQ_OK"); + sockets[fd, S_WAITS] = S_WAITS_NOT; + sockets[fd, S_WAIT_DATA] = 0; + ++sockets[fd, S_WRITTEN]; + if (sizeof(output)) flush(ufd); + callback(ufd, SOCKET_WRITTEN, + sockets[fd, S_TO_WRITE] == sockets[fd, S_WRITTEN]); + return; + + case ERQ_E_WOULDBLOCK: + // The xerq could not handle the sent data - this condition + // could never happen. However, if it happens we have to resend + // the last packet after some time. We just put it back in the + // output queue and wait for another ERQ_OK. + // If you have problems with sockets that seem to freeze after a + // wouldblock (which indicates a bad erq implementation), you could + // try and start a resend callout here. + if (!sockets[fd, S_WAIT_DATA]) { + // something went extremly wrong, there were several packets + // sent without waiting for erq response. Original data is + // lost already. Mind, this is a 'could never happen' case + // within a 'could never happen' case ;o)) + // + // Just do nothing. + } else + output = ({ sockets[fd, S_WAIT_DATA] }) + output; // back on stack + sockets[fd, S_WAITS] = S_WAITS_BLOCK; + sockets[fd, S_WAIT_DATA] = 0; + callback(ufd, SOCKET_ERROR, note_err("ERQ_E_WOULDBLOCK", msg, fd)); + return; + + case ERQ_E_TICKET: + callback(ufd, SOCKET_ERROR, note_err("ERQ_E_TICKET", msg, fd)); + break; + + case ERQ_E_PIPE: + // should only happen with childs + callback(ufd, SOCKET_ERROR, note_err("ERQ_E_PIPE", msg, fd)); + break; + + case ERQ_E_UNKNOWN: + callback(ufd, SOCKET_ERROR, note_err("ERQ_E_UNKNOWN", msg, fd)); + break; + + default: + callback(ufd, SOCKET_ERROR, note_err("unknown response", msg, fd)); + break; + } + + // if we get here an error occured. the erq closed the socket already + if (member(sockets, fd)) sockets[fd, S_STATE] = S_CLOSING; + callback(ufd, SOCKET_CLOSE, 0); + socket_close(ufd); +} + +// special cb for accept +// the xerq sends ERQ_E_TICKET also if the socket has no pending +// connection :-/ because we cannot distinguish that to a wrong +// ticket we just assume here it must be the first. +static void accept_cb(int* msg, int ufd) { + int fd; + if (msg[0] != ERQ_E_TICKET) return socket_cb(msg, ufd); + if (!m_contains(&fd, used_fd, ufd)) return; // vanished + if (member(sockets, sockets[fd, S_LISTEN_FD])) + sockets[sockets[fd, S_LISTEN_FD], S_PENDING] = 0; + sockets[fd, S_STATE] = S_CLOSING; + callback(ufd, SOCKET_NOPEND, 0); + note_err("SOCKET_NOPEND", msg, fd); + callback(ufd, SOCKET_CLOSE, 0); + socket_close(ufd); +} + +// the function calls the user object on new data or errors +static void callback(int ufd, int action, mixed args) { + int fd; + mixed data, item; + + debug("sockD::callback(%O, %O, %O)", fd, action, args); + if (!m_contains(&fd, used_fd, ufd) || !member(sockets, fd)) + return; // vanished + + // automatic delayed write + data = sockets[fd, S_PENDING]; + if (pointerp(data) && action == SOCKET_READY) { + foreach (item : data) socket_write(ufd, item[0], item[1]); + sockets[fd, S_PENDING] = sizeof(item); + } + else if (intp(data) && data > 0 && action == SOCKET_WRITTEN) { + sockets[fd, S_PENDING] = data - 1; + } + if (!sockets[fd, S_SOCKOBJ] || !sockets[fd, S_OBJECT]) { + if (!data && sockets[fd, S_STATE] != S_CLOSING) socket_close(ufd); + return; + } + + if (action == SOCKET_READ && sockets[fd, S_OPTS] & SOCKET_MUDMODE) { + args = to_array(args); // unquote args + sockets[fd, S_SOCKOBJ]->so_get_mudmode(args); + return; + } + apply(sockets[fd, S_CALLBACK], sockets[fd, S_SOCKOBJ], action, args); +} + + +// send a message trough the network (buffered) +static void sendbuf(int ufd, int* data, int offset) { + int fd; + // debug("sockD::sendbuf(%O, %O)", ufd, data); + debug("sockD::sendbuf(%O)", ufd); + if (!m_contains(&fd, used_fd, ufd)) return; // vanished + output += ({ ({ ufd, data, offset }) }); +} + +// Flush the message buffer for socket ufd. +// +// Xerq works as follows: +// 1 Erq gets new data +// 2 Erq tries to send data packet +// 3 Erq returns OK if successfull -=> continue at 1 +// 4 Erq returns INCOMPLETE. Rest of packet is buffered and sent +// when possible. +// 5 Erq returns OK if all buffered data could be written (*new*) +// 6 Continue at 1 +// +// There is only one packet buffered inside the erq for every socket. +// If you try to send a packet while one is in the queue already, the erq +// returns WOULDBLOCK and the new packet is discarded! +static void flush(int ufd) { + int ret, i, n, fd; + int* data; + + debug("sockD::flush(%O)", ufd); + // debug(output); + + n = sizeof(output); + if (!n) { + debug("nothing to send"); + return; + } + + // remove buffered data if socket is gone + if (!m_contains(&fd, used_fd, ufd) || !member(sockets, fd)) { + for (;n--;) { + if (output[n][OUT_UFD] != ufd) continue; + debug("discarding %O -> %O", ufd, output[0][OUT_DATA]); + output[n..n] = ({}); + } + return; + } + + if (sockets[fd, S_WAITS]) { + debug("socket busy"); + return; + } + + // find socket's data + for (; i < n; i++) { + if (output[i][OUT_UFD] == ufd) break; + } + if (i == n) { + debug("no data pending"); + return; + } + + sent += sizeof(output[i][OUT_DATA]); + data = sockets[fd, S_TICKET] + output[i][OUT_DATA]; + debug("sending"); + ret = send_erq(ERQ_SEND, data, + lambda(({ 'msg }), ({ #'write_cb, 'msg, ufd, output[i][OUT_SIZE] }))); + if (!ret) { + debug("got send_erg() error, retry in 1 second"); + call_out("flush", 1, ufd); + return; + } + sockets[fd, S_WAITS] = S_WAITS_ERQ; + sockets[fd, S_WAIT_DATA] = output[i..i]; + output[i..i] = ({}); +} + +// mudmode is an invention of MudOS. We have to simulate it here in +// some way or another. Its quite similar to ldmuds save_value() but +// does not change "\n" to "\\n" etc. +static string to_mudmode(mixed data) { + int num, i, len; + + // use save_value(data)[5..<2] with pre 3.2.10 drivers + data = save_value(data, 0)[5..<2]; + len = strlen(data); + + for (i=0; i<len; i++) { + if (data[i] == '\\') { + num++; + continue; + } + if (!num) continue; + if (num & 1) { + switch (data[i]) { + case 'r': data[i-1..i] = "\r"; len--; i--; break; + case 'f': data[i-1..i] = "\f"; len--; i--; break; + case 'v': data[i-1..i] = "\v"; len--; i--; break; + case 'n': data[i-1..i] = "\n"; len--; i--; break; + case 't': data[i-1..i] = "\t"; len--; i--; break; + case 'b': data[i-1..i] = "\b"; len--; i--; break; + case 'a': data[i-1..i] = "\a"; len--; i--; break; + } + } + num = 0; + } + + return data; +} + +mixed from_mudmode(string data) { + return restore_value("#0:0\n"+data+"\n"); +} + +// this is inside the socket object to collect full mudmode packets +void so_get_mudmode(int* data) { + mixed mix; + string err; + int i; + if (object_name(PO) != SOCKETD) + RAISE_ERROR("privilege violation: so_get_mudmode()\n"); + while (sizeof(data)) { + if (!so_bufs || !intp(so_bufs)) { + if (!so_bufs) so_bufs = ({}); + i = min(sizeof(data), 4); + i -= sizeof(so_bufs); + so_bufs += data[0..i-1]; + data = data[i..]; + if (sizeof(so_bufs) == 4) { + so_bufs = (((((so_bufs[0] & 0xff)) << 8 + | (so_bufs[1] & 0xff)) << 8 + | (so_bufs[2] & 0xff)) << 8 + | (so_bufs[3] & 0xff)); + debug("mudmode packet size ", so_bufs); + // String length is critical here, one string has to hold the + // complete packet. It seems that modmode is working with rather + // small packets (< 1kb) which fit nicely in a chararray, but + // we dont want do depend on that (and use strings). + } + else break; + if (so_bufs == 0) + debug("strange size, isn't it?"); + } + if (!so_buf) so_buf = ""; + i = sizeof(data); + if (i >= so_bufs) { + if (data[so_bufs-1] == 0) + so_buf += to_string(data[0..so_bufs-2]); + else + so_buf += to_string(data[0..so_bufs-1]); + data = data[so_bufs..]; + err = catch(mix = from_mudmode(so_buf)); + so_buf = ""; + so_bufs = 0; + if (err) { // invalid packet + funcall(sockets[so_fd, S_CALLBACK], ME, SOCKET_ERROR, + "mudmode protocoll violation"); + SOCKETD->socket_close(so_ufd); + return; + } + funcall(sockets[so_fd, S_CALLBACK], ME, SOCKET_READ, mix); + } else { + so_buf += to_string(data); + so_bufs -= i; + debug("... still data pending"); + break; // no data left + } + } +} + +// different handling of removal for master and clones +int remove() { + if (clonep()) { + SOCKETD->socket_close(so_ufd); + destruct(ME); + return 1; + } + + if (object_name(PO) != __MASTER_OBJECT__ && !SPECIAL_PREVILEGE) { + printf("DONT DO THAT!\n"); + return 0; + } + + if (first_inventory()) { + debug("*** going to remove socketd... (3 sec)"); + map(m_indices(used_fd), #'socket_close); + call_out("do_remove", 3); + } else destruct(ME); + return 1; +} + +static void do_remove() { + debug("*** done"); + destruct(ME); +} + +////// +// internal helper functions + +// which objects may create sockets +static int valid_socket(object ob) { + string on, v; + + on = object_name(ob); + if (!valids) valids = VALID_SOCKETS; + foreach (v : valids) + if (!strstr(on, v)) return 1; + return 0; +} + +// convert message to ascii +// values are signed -128 .. 127 +static string to_ascii(int* msg) { + msg -= ({ 0 }); + return to_string(msg); +} + +// some erq-error occured, log it +static mixed* note_err(string str, int* msg, int fd) { + string who, extra, e2; + + if (sockets[fd, S_OBJECT]) who = to_string(sockets[fd, S_OBJECT]); + else who = "destructed object"; + + if (msg[0] == ERQ_E_UNKNOWN) { + extra = ({ + // all errno-codes + // use list according to your system (this is linux) + "??? not used", + "EPERM Operation not permitted", + "ENOENT No such file or directory", + "ESRCH No such process", + "EINTR Interrupted system call", + "EIO I/O error", + "ENXIO No such device or address", + "E2BIG Arg list too long", + "ENOEXEC Exec format error", + "EBADF Bad file number", + "ECHILD No child processes", // 10 + "EAGAIN Try again", + "ENOMEM Out of memory", + "EACCES Permission denied", + "EFAULT Bad address", + "ENOTBLK Block device required", + "EBUSY Device or resource busy", + "EEXIST File exists", + "EXDEV Cross-device link", + "ENODEV No such device", + "ENOTDIR Not a directory", // 20 + "EISDIR Is a directory", + "EINVAL Invalid argument", + "ENFILE File table overflow", + "EMFILE Too many open files", + "ENOTTY Not a typewriter", + "ETXTBSY Text file busy", + "EFBIG File too large", + "ENOSPC No space left on device", + "ESPIPE Illegal seek", + "EROFS Read-only file system", // 30 + "EMLINK Too many links", + "EPIPE Broken pipe", + "EDOM Math argument out of domain of func", + "ERANGE Math result not representable", + "EDEADLK Resource deadlock would occur", + "ENAMETOOLONG File name too long", + "ENOLCK No record locks available", + "ENOSYS Function not implemented", + "ENOTEMPTY Directory not empty", + "ELOOP Too many symbolic links encountered", // 40 + "??? not used", + "ENOMSG No message of desired type", + "EIDRM Identifier removed", + "ECHRNG Channel number out of range", + "EL2NSYNC Level 2 not synchronized", + "EL3HLT Level 3 halted", + "EL3RST Level 3 reset", + "ELNRNG Link number out of range", + "EUNATCH Protocol driver not attached", + "ENOCSI No CSI structure available", // 50 + "EL2HLT Level 2 halted", + "EBADE Invalid exchange", + "EBADR Invalid request descriptor", + "EXFULL Exchange full", + "ENOANO No anode", + "EBADRQC Invalid request code", + "EBADSLT Invalid slot", + "??? not used", + "EBFONT Bad font file format", + "ENOSTR Device not a stream", // 60 + "ENODATA No data available", + "ETIME Timer expired", + "ENOSR Out of streams resources", + "ENONET Machine is not on the network", + "ENOPKG Package not installed", + "EREMOTE Object is remote", + "ENOLINK Link has been severed", + "EADV Advertise error", + "ESRMNT Srmount error", + "ECOMM Communication error on send", // 70 + "EPROTO Protocol error", + "EMULTIHOP Multihop attempted", + "EDOTDOT RFS specific error", + "EBADMSG Not a data message", + "EOVERFLOW Value too large for defined data type", + "ENOTUNIQ Name not unique on network", + "EBADFD File descriptor in bad state", + "EREMCHG Remote address changed", + "ELIBACC Can not access a needed shared library", + "ELIBBAD Accessing a corrupted shared library", // 80 + "ELIBSCN .lib section in a.out corrupted", + "ELIBMAX Attempting to link in too many shared libraries", + "ELIBEXEC Cannot exec a shared library directly", + "EILSEQ Illegal byte sequence", + "ERESTART Interrupted system call should be restarted", + "ESTRPIPE Streams pipe error", + "EUSERS Too many users", + "ENOTSOCK Socket operation on non-socket", + "EDESTADDRREQ Destination address required", + "EMSGSIZE Message too long", // 90 + "EPROTOTYPE Protocol wrong type for socket", + "ENOPROTOOPT Protocol not available", + "EPROTONOSUPPORT Protocol not supported", + "ESOCKTNOSUPPORT Socket type not supported", + "EOPNOTSUPP Operation not supported on transport endpoint", + "EPFNOSUPPORT Protocol family not supported", + "EAFNOSUPPORT Address family not supported by protocol", + "EADDRINUSE Address already in use", + "EADDRNOTAVAIL Cannot assign requested address", + "ENETDOWN Network is down", // 100 + "ENETUNREACH Network is unreachable", + "ENETRESET Network dropped connection because of reset", + "ECONNABORTED Software caused connection abort", + "ECONNRESET Connection reset by peer", + "ENOBUFS No buffer space available", + "EISCONN Transport endpoint is already connected", + "ENOTCONN Transport endpoint is not connected", + "ESHUTDOWN Cannot send after transport endpoint shutdown", + "ETOOMANYREFS Too many references: cannot splice", + "ETIMEDOUT Connection timed out", // 110 + "ECONNREFUSED Connection refused", + "EHOSTDOWN Host is down", + "EHOSTUNREACH No route to host", + "EALREADY Operation already in progress", + "EINPROGRESS Operation now in progress", + "ESTALE Stale NFS file handle", + "EUCLEAN Structure needs cleaning", + "ENOTNAM Not a XENIX named type file", + "ENAVAIL No XENIX semaphores available", + "EISNAM Is a named type file", // 120 + "EREMOTEIO Remote I/O error", + "EDQUOT Quota exceeded", + "ENOMEDIUM No medium found", + "EMEDIUMTYPE Wrong medium type", })[msg[1]]; + + debug(str + " (%O) %O (%O) for %O", msg[0], e2, msg[1], who); + } + else debug(str + " (%O) for %O", msg[0], who); + + + log_file(SOCKETLOG, ctime()[4..19] + str + " (" + msg[0] + ") " + extra||"" + + "for " + who + "\n"); + + return ({ str, msg, extra }); +} + +object _debug(int on) { + if (!SPECIAL_PREVILEGE) return 0; + if (!on) return debugger = 0; + return debugger = this_interactive(); +} + +static void debug(varargs mixed* xx) { + string txt; + mixed y, x; + int i; + + if (!debugger) return; + + x = xx + ({}); // strange behavior in 3.3's foreach + if (stringp(x[0])) { + txt = x[0]; + x = x[1..]; + } + else txt = ""; + + foreach (y : x) { + i = strstr(txt, "%O"); + if (i >= 0) txt[i..i+1] = MIXED2STR(y); + else txt += " " + MIXED2STR(y); + } + + tell_object(debugger, txt + "\n"); +} + +// you could send a wizcommand here +public int netstat(string arg) { + string proto, mode, state, h_p; + object so; + int fd; + + if (stringp(arg)) { + arg = trim(arg); + fd = to_int(arg); + if (!member(sockets, fd)) { + printf("No socket with file descriptor '" + arg + "'.\n"); + return 1; + } + printf("Full information on socket fd " + fd + "\n"); + printf(" object: " + to_string(sockets[fd, S_SOCKOBJ]) + "\n"); + printf(" type: " + ({ "TCP_OPEN", "TCP_LISTEN", "?", "UDP", "?", + "TCP_ACCEPT"})[sockets[fd, S_TYPE]] + "\n"); + printf(" ticket: " + + implode(map(sockets[fd, S_TICKET], #'to_string), ",") + "\n"); + printf(" state: "+ ({ "UNCONNECTED", "CONNECTED", "LISTEN", "LISTEN", + "CLOSING", "ACCEPT" })[sockets[fd, S_STATE]] + "\n"); + printf(" option: " + ({ "ASCII", "BINARY", "?", + "MUDMODE" })[sockets[fd, S_OPTS]] + "\n"); + printf(" callback: %O\n", sockets[fd, S_CALLBACK]); + printf(" creater: " + to_string(sockets[fd, S_OBJECT]) + "\n"); + printf(" created: " + ctime(object_time(sockets[fd, S_SOCKOBJ])) + "\n"); + printf(" owner id: " + sockets[fd, S_OWNER] + "\n"); + printf(" packets to write: " + sockets[fd, S_TO_WRITE] + "\n"); + printf(" packets written: " + sockets[fd, S_WRITTEN] + + " (" + (sockets[fd, S_TO_WRITE] - sockets[fd, S_WRITTEN]) + + " remaining)\n"); + printf(" packets received: " + sockets[fd, S_RECEIVED] + "\n"); + printf(" if applicable:\n"); + printf(" host: " + sockets[fd, S_HOST] + "\n"); + printf(" port: " + sockets[fd, S_PORT] + "\n"); + printf(" listen fd: " + sockets[fd, S_LISTEN_FD] + "\n"); + printf(" listen port: " + sockets[fd, S_LPORT] + "\n"); + return 1; + } + + printf("fd proto mode address local state " + "pend owner\n"); + foreach (fd : sort_array(m_indices(sockets),#'>)) { + if (!sockets[fd, S_OBJECT]) { + m_delete(sockets, fd); + continue; + } + proto = ({ "TCP_OPEN", "TCP_LISTEN", 0, "UDP", 0, + "TCP_ACCEPT"})[sockets[fd, S_TYPE]]; + if (sockets[fd, S_OPTS] == 0) mode = "ASCII"; + else if (sockets[fd, S_OPTS] & 2) mode = "MUDMODE"; + else mode = "BINARY"; + + state = ({ "UNCONNECTED", "CONNECTED", "LISTEN", "LISTEN", "CLOSING", + "ACCEPT" })[sockets[fd, S_STATE]]; + if (sockets[fd, S_TYPE] == TCP_ACCEPT + && sockets[fd, S_STATE] != S_CONNECTED) h_p = "(unknown)"; + else { + h_p = sockets[fd, S_HOST]; + if (h_p) h_p += " " + sockets[fd, S_PORT]; + else h_p = "---"; + } + + printf("%2d %-10s %-7s %-21s %-7s %-11s %c %-10s\n", + fd, proto, mode, h_p, + sockets[fd, S_LPORT] ? "("+sockets[fd, S_LPORT]+")" : "", + state, sockets[fd, S_PENDING] ? '*' : ' ', + sockets[fd, S_OWNER] + regreplace(object_name(sockets[fd, S_OBJECT]), + ".*/([^/#]+).*", ":\\1", 0)); + } + + if (!sizeof(sockets)) printf(" <-- empty list -->\n"); + printf("%d socket objects for %d sockets\n", sizeof(all_inventory()), + sizeof(sockets)); + printf("%d bytes send, %d bytes received\n", sent, rcvt); + return 1; +} diff --git a/src/util/xerq/lpc/socketd.man b/src/util/xerq/lpc/socketd.man new file mode 100644 index 0000000..def66fb --- /dev/null +++ b/src/util/xerq/lpc/socketd.man @@ -0,0 +1,278 @@ +CONCEPT + Sockets and the socket daemon + +DESCRIPTION + If you want to connect to another computer on the internet + you would like to use sockets. Sockets are not part of the + driver so there has to be someting in the lib. Here it + is: the socket daemon. + + It helps you to create and maintain state of your connection + with various protocols and different computers. + + What sockets are and how you use them is not subject of this + text. Maybe the examples help you but be encouraged to read + some real text on them. + + Creating a socket + ~~~~~~~~~~~~~~~~~ + You could create internet domain sockets with tcp or udp + protocol. Listening and sending of data is possible. Also + there is on protocol overlying tcp available: mudmode. + + To create a socket you call the daemon which will return you + a socket object. All further handling is done by that + object: + + #include <daemon/socket.h> + + sock_ob = (object) SOCKETD->New(...); + + The full prototype of New() is as follows: + object New(int type, string host, int port, closure cb, int opts) + + The Type is one of: + TCP_OPEN An outgoing tcp connection. + TCP_LISTEN Listen on a tcp port for incoming connections. + UDP An incoming or outgoing udp connections. + + The Host of the destination could be specified as an IP address + like "139.18.11.86" or via a DNS name which will be resolved + first "wl.mud.de". Note that it is used only for TCP_OPEN and has + to be zero for the other types. + + The Port is an Integer: + TCP_OPEN The port on the remote computer we want to + connect to. Its not possible to choose the packet's + source port, a random number will be used. + TCP_LISTEN The port on which we will await connections. + UDP The port on which we will listen and also the + port to send packets _from_. + It is not possible to send udp packets without + listening at the port we want as source. + + The callback closure cb gets all the data and status or error + messages of that socket. It is described further down. + + The Opts may be + SOCKET_ASCII which is also the default. Its not possible to + receive data with embedded \000 which are filtered. + You will get the data as strings. + SOCKET_BINARY Here is all data possible. Because its not (yet) + possible to have \000 in strings in lpc you will + get the data as array of chars (ints). + SOCKET_MUDMODE This is a layer over TCP whichs allows you to send + complex LPC data types rather than limited strings. + The receiver is most likely also a mud where the + same data is reconstructed. It is possible to send + mapbe ({ 3, 3.0, "hi" }) over the network and the + receiver will just get that (the mixed* array) + rather than a string. Mind that it is not possible + to send objectpointer. Also be careful with + double references which are not guaranteed to be + restored correctly. + + Using a socket + ~~~~~~~~~~~~~~ + To handle the socket you could call the following functions + in your socket object. They will return 1 if all seems to + be correct but real errors are reported via callback. + + int Write(mixed data) + The given data is written to the socket. If nothing goes wrong + it will end up on the far partner's computer. The data may + be a string or an array of integers (which may contain zeros). + If the socket is in SOCKET_MUDMODE any lpc structure may be + written (without object pointer). + Note that SOCKET_ASCII/SOCKET_BINARY is not interpreted here. + + int Send(string host, int port, mixed msg) + This is the same but used on UDP sockets only. Because UDP is + connectionless you have to give your destination on each Send(). + Host and port are specified like for New(). + The UDP packet size is limited to MAX_SEND bytes. If the msg + requires more space (quite unpredictable in MUDMODE) it is + split into several packages. The receiver must handle that + or you should not send that big a message. + Sending MUDMODE UDP is not (yet) possible. + + object Accept(closure acc_cb) + Opens a pending connection on a listend to socket. You have to + call it in the main listen socket object. + It returns you a new socket object for that connection. + All data and status messages of the new connection will be + handled via acc_cb, which may be the same function as your + main callback function. + The listening socket could be closed after the new connection + is fully established, if you want to handle only one connection + at a time. + + int Close() + The connection is ended and the socket object removed. + If you use remove() on the socket object an emergency Close() + is called but it is better to do this right and never call + remove() on the socket object. + + mixed* State() + Returns you an array with Information on that connection. + S_SOCKOBJ The object itself (really useless info, isn't it?) + S_TYPE The type of the socket. Additional to TCP_OPEN, + TCP_LISTEN and UDP there is TCP_ACCEPT. That is the + type of accepted connections. + S_TICKET An integer array holding the ticket of that object + for xerq communication. Not needed in normal cases. + S_STATE The state of the socket: + S_UNCONNECTED No connection (yet) maybe we wait + for the DNS resolving. + S_CONNECTED We are connected (yeah!). + S_LISTEN The socket listens for connections. + S_UDP The socket listens for connections + and we may send packages out. + S_CLOSING The socket is or will be closed in + short time. Don't do anything but + clear up anymore. + S_OPTS The opts as described above. Mind that the opts + are bits and setting SOCKET_MODMODE will set + SOCKET_BINARY automatically. + S_HOST The remote host. + S_PORT The remote port. + S_LPORT The local port. + S_CALLBACK The callback closure. + S_OBJECT The object the callback closure is bound to. This + is the only one which could call the functions in + the socket object. + S_PENDING Pending data or number of data to be sent. Don't use. + (It's the preconnection data buffer.) + S_OWNER The uid of S_OBJECT. + S_LISTEN_FD Used internally on accepted connections. The file + descriptor of the listening socket. Is overwritten + with S_PORT after connect. + S_TO_WRITE How many packets are to be written to the erq. + Note that the erq could handle only small chunks of + data so this is not the number of Write()s or + Send()s. + S_WRITTEN How many of the S_TO_WRITE packets were acknoledged + by the erq with SOCKET_WRITTEN. If both numbers are + equal all data should be in the erq's queue. + S_RECEIVED How many data packets were received from the erq. + S_WAITS The sockets wait state as follows: + S_WAITS_NOT no waiting + S_WAITS_ERQ packet send to erq, waiting for reply + S_WAITS_INCOM erq replied SOCKET_INCOMPLETE, + waiting for socket to unblock + S_WAITS_BLOCK erq replied ERQ_E_WOULDBLOCK + waiting for socket to unblock + + The callback system + ~~~~~~~~~~~~~~~~~~~ + + Whenever something happens to your sockets it will be send to + your callback closure. It should have the following prototype: + void cb(object sock_obj, int action, extra1, extra2, extra3) + + The sock_obj specifies the connection on which the action took + place. This is handy if you handle multiple sockets over one + callback. + + The following actions exist: + SOCKET_READY: The socket is ready to receive or send data. + No extra info is given except when the socket + is one opened by Accept(): + extra1: The listening socket object (stupid). + extra2: The remote host (string). + extra3: The remote port (int). + + SOCKET_ACCEPT: A listen port detected an incoming connection. + you could accept it with Accept(). + + SOCKET_READ: Incoming data is ready. + extra1: The data. + extra2: The remote host (UDP only). + extra3: The remote port (UDP only). + + SOCKET_WRITTEN: Some data was sent out successful. + Note that your data will be chunkized so that + one Write() may result in several callbacks. + If all pending data is written, extra1 is + set to 1. + extra1: All data written if set. + + SOCKET_INCOMPLETE: Not all data could be written. The xerq is + buffering the rest and will notify us with + SOCKET_WRITTEN if the writing is complete. + This is informational only, you do not need + to take any action or notice. + extra1: Amount of data of the actual chunk + which could be written. + extra2: Amount of data of whole LPC chunk + which could be written. + Note that there might be several such callbacks + until the packet is written completely. + + SOCKET_CLOSE: This is called when the connection is closed + either from you or the other side. + + SOCKET_ERROR: An error occured. + extra1: Short error message (of the xerq)(string) + extra2: The xerq packet with the error or zero + extra3: Description of the error ERQ_E_UNKNOWN. + If extra2 is an array (of int) you will find the + xerq error code in extra2[0]. See erq(C) also. + + SOCKET_NOPEND: You tried to accept on a listening socket + where no pending connection is (anymore). This + is sent to the socket object you got from the + Accept(). That object will be destroyed + afterwards. + + Principle of operation + ~~~~~~~~~~~~~~~~~~~~~~ + + Here is a raw sketch of how sockets are supposed to work. + All three szenarios are described. Its only a sketch NOT code! + + * outgoing connection + + socket = New(TCP_OPEN) + callback SOCKET_READY + socket->Write("hello\n") + callback SOCKET_WRITTEN 1 + callback SOCKET_READ, "hi you\n" + socket->Close() + callback SOCKET_CLOSE + + * incoming connection + + socket = New(TCP_LISTEN) + callback SOCKET_READY + callback SOCKET_ACCEPT + sock_2 = socket->Accept() + callbac2 SOCKET_READY + sock_2->Write("hello\n") + callbac2 SOCKET_WRITTEN 1 + callback SOCKET_ACCEPT (but we ignore that) + callbac2 SOCKET_READ, "hi you\n" + sock_2->Write("bye\n"); + sock_2->Close(); + socket->Close(); + callbac2 SOCKET_WRITTEN 1 (see the callbacks are + callbac2 SOCKET_CLOSE asynchronous) + callback SOCKET_CLOSE + + We could have done sock_3 = socket->Accept() after the second + SOCKET_ACCEPT to handle to connections at a time. + + * UDP connection + + socket = New(UDP) + callback SOCKET_READY + socket->Send("whos there", host1, port1); + callback SOCKET_WRITTEN 1 + socket->Send("and there?\n\n", host2, port2); + callback SOCKET_WRITTEN 1 + callback SOCKET_READ, "hi you\n", host1, port1 + socket->Close() + callback SOCKET_CLOSE + +SEE ALSO + erq(C) diff --git a/src/util/xerq/lpc/telnet_ob.c b/src/util/xerq/lpc/telnet_ob.c new file mode 100644 index 0000000..2f05cb6 --- /dev/null +++ b/src/util/xerq/lpc/telnet_ob.c @@ -0,0 +1,216 @@ +#include "socket.h" +#include <errno.h> + +#define DEFAULT_PORT 23 + +object user; +string buff="", + host, + log_file; +int sock, + port; +status attached, + connected; + +static void callback(int fd, int act, mixed a, mixed b); +static void timeout(); + +void start(string h, int p) +{ + if (!adminp(this_player())) return 0; + sock=(int)SOCKETD->socket_connect(h, p, #'callback); + connected=0; + printf("Connecting to %s port %d\n", h, p); + user=this_player(); + host=h; + port=p; + attached=1; + call_out(#'timeout, 15); + input_to("input"); + return; +} + +void reattach() +{ + printf("[telnet: Reattaching to %s%c%s]\n", + host, + port == DEFAULT_PORT ? 0 :' ', + port == DEFAULT_PORT ? "":to_string(port)); + attached=1; + write(buff); + buff=""; + input_to("input"); + return; +} + +void tell_user(string msg) +{ + if (attached) + tell_object(user, msg); + else + buff=sprintf("%s%s", buff, msg); + if (!attached && member(msg, '') != -1) + tell_object(user, sprintf("[telnet: Beep from %s%c%s]\n", + host, + port == DEFAULT_PORT ? 0 :' ', + port == DEFAULT_PORT ? "":to_string(port))); + if (log_file) + write_file(log_file, msg); + return; +} + +static void timeout() +{ + if (connected) return; + tell_user("telnet: connection timed out.\n"); + if (!attached) + tell_object(user, buff); + sock=-1; + user=0; + destruct(this_object()); +} + +void callback(int fd, int act, mixed a, mixed b) +{ + switch(act) { + case SOCKET_READY: + tell_user("telnet: connected.\n"); + remove_call_out(#'timeout); + connected=1; + break; + case SOCKET_READ: + tell_user(a); + break; + case SOCKET_CLOSE: + tell_user("telnet: connection closed.\n"); + if (!attached) + tell_object(user, buff); + sock=-1; + user=0; + connected=0; + destruct(this_object()); + break; + case SOCKET_ERROR: { + string err; + if (a == ERQ_E_NOTFOUND) err="Unknown host"; + else switch(b) { + case ECONNREFUSED: + err="Connection Refused"; + break; + case EHOSTUNREACH: + err="Host Unreachable"; + break; + case ENETUNREACH: + err="Net Unreachable"; + break; + default: + err=sprintf("Error %d", b); + break; + } + tell_user(sprintf("telnet: %s\nclosing connection.\n", err)); + if (!attached) + tell_object(user, buff); + sock=-1; + user=0; + destruct(this_object()); + } + break; + } + return; +} + +void input(string str) +{ + if (sock<0) return; + if (str[0]=='') { + switch(str[1]) { + case 'c': { + if (!log_file) + write("telnet: Not logging session.\n"); + else { + printf("telnet: Stopped logging session to: %s.\n", log_file); + log_file=0; + } + input_to("input"); + return; + } + case 'd': { + tell_object(user, "Detached. Type 'telnet' to resume.\n"); + attached=0; + return; + } + case 'l': { + if (!str[2]) { + if (log_file) + printf("telnet: Logging session to: %s.\n", log_file); + else + write("telnet: Not logging session.\n"); + } else { + str=eval_path(trimstr(str[2..])); + if (file_size(str) == -2) + str=sprintf("%s/telnet_log", str); + printf("telnet: Logging session to: %s.\n", str); + log_file=str; + } + input_to("input"); + return; + } + case 'q': { + SOCKETD->socket_close(sock); + tell_user("telnet: connection closed.\n"); + if (!attached) + tell_object(user, buff); + user=0; + sock=-1; + destruct(this_object()); + return; + } + case 's': { + str=eval_path(trimstr(str[2..])); + if (file_size(str) < 0) + printf("telnet: Could not find file: %s.\n", str); + else if (connected) { + string *lines; + lines=explode(read_file(str), "\n"); + tell_user(sprintf("telnet: Sending file: %s.\n", str)); + for(; sizeof(lines); lines=lines[1..]) + SOCKETD->socket_write(sock, sprintf("%s\n", lines[0])); + tell_user("telnet: File sent.\n"); + } + input_to("input"); + return; + } + case '!': { + str=str[1..]; + } + case '?': { + write("telnet: Escape commands:\n" + "All commands are preceeded by the escape (^[) character.\n" + "\n" + "c Close session log.\n" + "d Detach telnet session.\n" + "l<file> Open session log into <file>.\n" + "q Forcefully close telnet session.\n" + "s<file> Send a file to telnet session.\n" + "!<arg> Send '!<arg>' to remote host.\n" + "? This help page.\n"); + input_to("input"); + return; + } + } + } + if (connected) { + SOCKETD->socket_write(sock, str=sprintf("%s\n", str)); + if (log_file) + write_file(log_file, str); + } + input_to("input"); + return; +} + +status clean_up(status arg) +{ + if (!user) + destruct(this_object()); + return 1; +} diff --git a/src/util/xerq/lpc/udp.c b/src/util/xerq/lpc/udp.c new file mode 100644 index 0000000..422a0ac --- /dev/null +++ b/src/util/xerq/lpc/udp.c @@ -0,0 +1,43 @@ +#define PORT 6000 + +#include "socket.h" + +int fd; +object tp; + +#define reply(X) tell_object(tp, X); + +void cb(int fd, int act, mixed a, mixed b, mixed c) +{ + switch(act) { + case SOCKET_READY: + reply("Ready.\n"); + return; + case SOCKET_READ: + reply(sprintf("From %O %O:\n", b, c)); + reply(a); + return; + case SOCKET_ERROR: + reply(sprintf("Error: %d %d\n", a, b)); + return; + case SOCKET_CLOSE: + destruct(this_object()); + return; + } +} + +void reset(int arg) { + if (arg) return; + tp=this_player(); + fd=SOCKETD->socket_udp(PORT, #'cb); +} + +send(string str) +{ + SOCKETD->socket_sendto(fd, "127.0.0.1", PORT, str); +} + +destructor() +{ + SOCKETD->socket_close(fd); +} diff --git a/src/util/xerq/lpc/www/finger.c b/src/util/xerq/lpc/www/finger.c new file mode 100644 index 0000000..448c7f6 --- /dev/null +++ b/src/util/xerq/lpc/www/finger.c @@ -0,0 +1,10 @@ +string www_main(string *args) +{ + if (sizeof(args) != 1) return "<PLAINTEXT>Need to specify a name.\n"; + return sprintf( +"<TITLE>Finger: %s</TITLE>\n" +"<PLAINTEXT>%s", + args[0], "/cmds/std/_finger"->get_finger(args[0], 0)); +} + +status clean_up(status arg) { destruct(this_object()); } diff --git a/src/util/xerq/lpc/www/who.c b/src/util/xerq/lpc/www/who.c new file mode 100644 index 0000000..40f81ca --- /dev/null +++ b/src/util/xerq/lpc/www/who.c @@ -0,0 +1,23 @@ +string www_main(string *args) +{ + string data, *info; + + info="/cmds/std/_who"->who_data()[2..<2]; + data=sprintf( +"<TITLE>Timewarp Who List</TITLE>\n" +"<BODY>\n" +"<H1 align=center>Timewarp Who List</H1>\n" +"\n" +"There are %d people currently logged in.\n" +"<PRE><HR>\n" +"%s\n" +"<HR></PRE>\n" +"<ADDRESS><A HREF=\"http://quark.gmi.edu/people/People.html\">\n" +"<IMG SRC=\"http://quark.gmi.edu/pics/buttons/people_page.gif\">\n" +"Return to Timewarp's People Page</A>.</ADDRESS>\n" +"</BODY>\n", + sizeof(info), implode(info,"")); + return data; +} + +status clean_up(status arg) { destruct(this_object()); } diff --git a/src/util/xerq/socket.c b/src/util/xerq/socket.c new file mode 100644 index 0000000..e69d335 --- /dev/null +++ b/src/util/xerq/socket.c @@ -0,0 +1,916 @@ +/*--------------------------------------------------------------------------- + * XErq - Socket functions. + * (C) Copyright 1995 by Brian Gerst. + * (C) Copyright 2001 by Brian Gerst, Frank Kirschner, Lars Duening. + *--------------------------------------------------------------------------- + * This module implements the communication requests, and also contains + * the functions handling socket_t structures. + *--------------------------------------------------------------------------- + */ + +#include "defs.h" + +#if defined(_AIX) +typedef unsigned long length_t; +#elif defined(__INTEL_COMPILER) || defined (__GNUC__) +typedef socklen_t length_t; +#else +typedef int length_t; +#endif + +static int send_auth (auth_t *ap); + +/*-------------------------------------------------------------------------*/ +socket_t * +new_socket(int fd, char type) + +/* Create a socket_t of <type> for <fd>, assign it a ticket and add it to + * the socket list. + * Return the pointer to the socket structure. + */ + +{ + socket_t *sp; + + sp = malloc(sizeof(struct socket_s)); + XPRINTF((stderr, "%s New socket %p: fd %d\n", time_stamp(), sp, fd)); + sp->next = sockets; + sp->fd = fd; + sp->type = type; + sp->ticket.seq = (seq_number+=seq_interval); + sp->ticket.rnd = get_ticket(); + sp->queue = NULL; + sockets = sp; + return sp; +} /* new_socket() */ + +/*-------------------------------------------------------------------------*/ +static void +free_socket (socket_t *sp) + +/* The socket in structure <sp> has been closed already, now remove the + * structure from the socket list and free it and all still pending + * data. + */ + +{ + socket_t **spp; + equeue_t *qp, *qnext; + + XPRINTF((stderr, "%s Freeing socket %p\n", time_stamp(), sp)); + /* Remove the socket from the socket */ + for (spp = &sockets; *spp; spp = &(*spp)->next) + { + if (*spp != sp) + continue; + XPRINTF((stderr, "%s Unlinking socket %p\n", time_stamp(), sp)); + *spp = sp->next; + break; + } + + /* Free all pending queued data */ + for (qp = sp->queue; qp;) + { + XPRINTF((stderr, "%s Freeing queue %p\n", time_stamp(), qp)); + qnext = qp->next; + free(qp); + qp = qnext; + } + + free(sp); +} /* free_socket() */ + +/*-------------------------------------------------------------------------*/ +void +add_to_queue (equeue_t **qpp, char *data, int len, int32 hand) + +/* Add the message <data> of <len> bytes to the end of queue <qpp>. + */ + +{ + equeue_t *new; + + new = malloc(sizeof(struct equeue_s)+len); + XPRINTF((stderr, "%s New queue %p: data %p:%d, queue head %p (-> %p)\n" + , time_stamp(), new, data, len, qpp, *qpp)); + new->len = len; + new->pos = 0; + new->next = 0; + new->handle = hand; + memcpy(&new->buf, data, len); + while (*qpp) + qpp = &(*qpp)->next; + *qpp = new; +} /* add_to_queue() */ + +/*-------------------------------------------------------------------------*/ +int +flush_queue (equeue_t **qpp, int fd, int reply_handle) + +/* Try to write all pending data from queue <qpp> to socket <fd>. + * Return -1 if an error occured, and 0 if the queue could be emptied. + * Single queue elements which have been written are always removed. + */ + +{ + int l; + equeue_t *qp = *qpp, *next; + + XPRINTF((stderr, "%s Flush queue %p (-> %p) to %d\n" + , time_stamp(), qpp, *qpp, fd)); + do { + XPRINTF((stderr, "%s Flush queue entry %p, data %p:%d:%d\n" + , time_stamp(), qp, qp->buf, qp->pos, qp->len)); + do + l = write(fd, qp->buf+qp->pos, qp->len); + while (l==-1 && errno==EINTR); + XPRINTF((stderr, "%s Wrote %d of %d bytes.\n", time_stamp(), l, qp->len)); + if (l < 0) + return l; + if (l < qp->len) + { + qp->pos += l; + qp->len -= l; + break; + } + XPRINTF((stderr, "%s Freeing queue entry %p.\n", time_stamp(), qp)); + if (reply_handle) { + char r_ok[] = { ERQ_OK, 0 }; + reply1(qp->handle, r_ok, sizeof(r_ok)); + } + next = qp->next; + free(qp); + qp = next; + } while(next); + + XPRINTF((stderr, "%s Re-setting queue to entry %p.\n", time_stamp(), qp)); + *qpp = qp; + return 0; +} /* flush_queue() */ + +/*-------------------------------------------------------------------------*/ +void +close_socket (socket_t *sp) + +/* Close the socket associated with <sp> and free the structure and all + * data. The function takes care that child_t structures referencing this + * socket are updated as well. + * Before the socket is closed, the proper message is sent back to + * the driver. + */ + +{ + child_t *chp; + socket_t *stmp; + int found = 0; + + XPRINTF((stderr, "%s Closing socket %p\n", time_stamp(), sp)); + + /* Check if the socket is still active */ + for (stmp = sockets; stmp; stmp = stmp->next) + if (stmp == sp) + { + found = 1; + break; + } + + if (!found) /* socket already closed */ + { + XPRINTF((stderr, "%s Socket %p already closed.\n", time_stamp(), sp)); + return; + } + + /* Depending on the socket type, handle the fluff + * depending on the socket. + */ + switch(sp->type) + { + case SOCKET_STDOUT: + { + for (chp = childs; chp; chp=chp->next) + if (chp->fd == sp) + break; + if (chp) + { + XPRINTF((stderr, "%s Remove 'fd' link from child %p.\n" + , time_stamp(), chp)); + chp->fd = NULL; + } + break; + } + + case SOCKET_STDERR: + { + for (chp = childs; chp; chp=chp->next) + if (chp->err == sp) + break; + if (chp) + { + XPRINTF((stderr, "%s Remove 'err' link from child %p.\n" + , time_stamp(), chp)); + chp->err = NULL; + } + break; + } + + case SOCKET_WAIT_AUTH: + case SOCKET_AUTH: + { + auth_t *ap = (auth_t *)sp; + XPRINTF((stderr, "%s Write auth info %p:%d\n" + , time_stamp(), ap->buf, ap->pos)); + write_32(ap->buf, ap->pos); + write_32((ap->buf)+4, ap->s.handle); + write1(ap->buf, ap->pos); + break; + } + + default: + { + char r[] = { ERQ_EXITED, 0 }; + reply1(sp->handle, r, sizeof(r)); + } + } + + close(sp->fd); + free_socket(sp); +} /* close_socket() */ + +/*-------------------------------------------------------------------------*/ +int +read_socket (socket_t *sp, int rw) + +/* The socket <sp> was flagged by select() as ready for reading (<rw> == 0) + * resp. writing (<rw> == 1). According to the type of socket take the + * appropriate action. + * + * If there is data pending on the socket, try to write it in any case. + * + * Return 0 on success, 1 if an error occured and the socket has been closed. + */ + +{ + char buf[ERQ_MAX_REPLY]; + int num; + + num = 0; + + XPRINTF((stderr, "%s Read socket %p (fd %d, type %d) , rw %d\n" + , time_stamp(), sp, sp->fd, sp->type, rw)); + + if (sp->queue) + flush_queue(&sp->queue, sp->fd, 1); + + switch(sp->type) + { + case SOCKET_LISTEN: + { + /* There is a connection pending */ + char r[] = { ERQ_STDOUT }; + + reply1keep(sp->handle, r, sizeof(r)); + sp->type = SOCKET_WAIT_ACCEPT; + XPRINTF((stderr, "%s Signaling driver to accept connction\n" + , time_stamp() )); + return 0; + } + + case SOCKET_WAIT_ACCEPT: + return 0; + + case SOCKET_UDP: + { + /* Read the data message and pass it on */ + + struct sockaddr_in addr; + length_t len; + + do { + char r[] = { ERQ_STDOUT }; + + len = sizeof(addr); + num = recvfrom(sp->fd, buf, ERQ_MAX_REPLY-20, 0, + (struct sockaddr *)&addr, &len); + if (num < 0 && errno==EINTR) + continue; + { int myerrno = errno; + XPRINTF((stderr, "%s Received UDP: %d bytes of %d.\n" + , time_stamp(), num, len)); + errno = myerrno; + } + if (num <= 0) + break; + replyn(sp->handle, 1, 4, + r, sizeof(r), + (char *) &addr.sin_addr.s_addr, 4, + (char *) &addr.sin_port, 2, + buf, num); + } while(1); + break; + } + + case SOCKET_WAIT_CONNECT: + { + if (rw) + { + /* Our opened TCP socket finally connected */ + + char r[] = { ERQ_OK }; + + XPRINTF((stderr, "%s Socket connected.\n" + , time_stamp() )); + sp->type = SOCKET_CONNECTED; + replyn(sp->handle, 1, 2, + r, sizeof(r), + (char *) &sp->ticket, TICKET_SIZE); + return 0; + } + XPRINTF((stderr, "%s Socket not connected yet.\n" + , time_stamp() )); + /* FALLTHROUGH */ + } + + case SOCKET_STDOUT: + case SOCKET_STDERR: + case SOCKET_CONNECTED: + { + /* Read data from the stream and pass it on */ + + char r_err[] = { ERQ_STDERR }; + char r_out[] = { ERQ_STDOUT }; + + XPRINTF((stderr, "%s Attempting to read data from socket.\n" + , time_stamp() )); + + do { + num = read(sp->fd, buf, ERQ_MAX_REPLY-14); + if (num < 0 && errno == EINTR) + continue; + { int myerrno = errno; + XPRINTF((stderr, "%s Received stream: %d bytes.\n" + , time_stamp(), num)); + errno = myerrno; + } + if (num <= 0) + break; + replyn(sp->handle, 1, 2, + (sp->type==SOCKET_STDERR) ? r_err : r_out, 1, + buf, num); + } while(1); + break; + } + + case SOCKET_WAIT_AUTH: + { + if (rw) + { + /* Our authd connection is finally there */ + + sp->type = SOCKET_AUTH; + return send_auth((auth_t *)sp); + } + /* FALLTHROUGH */ + } + + case SOCKET_AUTH: + { + auth_t *ap = (struct auth_s *)sp; + do { + /* Tell the driver what we got from the authd */ + + num = read(ap->s.fd, &ap->buf[ap->pos], sizeof(ap->buf)-ap->pos); + if (num < 0 && errno == EINTR) + continue; + { int myerrno = errno; + XPRINTF((stderr, "%s Received auth: %d bytes.\n" + , time_stamp(), num)); + errno = myerrno; + } + if (num <= 0) + { + close_socket(sp); + return 1; + } + ap->pos += num; + } while(1); + } + } /* switch(socket->type) */ + + if (!num) + { + /* We got EOF when reading data - the socket is no longer needed. + */ + + XPRINTF((stderr, "%s EOF when reading data.\n", time_stamp())); + close_socket(sp); + return 1; + } + + if (errno != EWOULDBLOCK +#if EWOULDBLOCK!=EAGAIN + && errno != EAGAIN +#endif + ) + { + int myerrno = errno; + XPRINTF((stderr, "%s Error %d when reading data.\n", time_stamp(), errno)); + errno = myerrno; + reply_errno(sp->handle); + close_socket(sp); + return 1; + } + + return 0; +} /* read_socket() */ + +/*-------------------------------------------------------------------------*/ +void +erq_send (char *mesg, int msglen) + +/* ERQ_SEND: send data to the socket identified by the ticket. + */ + +{ + ticket_t *ticket; + socket_t *sp; + int num; + char *data; + + /* Find the socket identified in the message */ + + if (msglen < 9+TICKET_SIZE) + { + char r_arglen[] = { ERQ_E_ARGLENGTH }; + reply1(get_handle(mesg), r_arglen, sizeof(r_arglen)); + return; + } + + ticket = (struct ticket_s *) (mesg+9); + data = mesg+9+TICKET_SIZE; + msglen -= (TICKET_SIZE+9); + + for (sp = sockets; sp; sp = sp->next) + if (!memcmp(ticket, &sp->ticket, TICKET_SIZE)) + break; + + if (!sp) + { + char r_ticket[] = { ERQ_E_TICKET }; + reply1(get_handle(mesg), r_ticket, sizeof(r_ticket)); + return; + } + + XPRINTF((stderr, "%s Send %d bytes to socket %p, type %d\n" + , time_stamp(), msglen, sp, sp->type)); + + /* Act according to the type of the socket */ + switch(sp->type) + { + case SOCKET_STDOUT: + case SOCKET_CONNECTED: + { + /* Send the data to the stream */ + + do + num = write(sp->fd, data, msglen); + while (num == -1 && errno == EINTR); + { int myerrno = errno; + XPRINTF((stderr, "%s Stream: Wrote %d bytes of %d.\n" + , time_stamp(), num, msglen)); + errno = myerrno; + } + break; + } + + case SOCKET_UDP: + { + /* Send the message to the specified address */ + + struct sockaddr_in addr; + + addr.sin_family=AF_INET; + memcpy(&addr.sin_addr.s_addr, data, 4); + memcpy(&addr.sin_port, data+4, 2); + data += 6; + msglen -= 6; + do + num = sendto(sp->fd, data, msglen, 0, (struct sockaddr *)&addr, + sizeof(addr)); + while(num == -1 && errno == EINTR); + { int myerrno = errno; + XPRINTF((stderr, "%s UDP: Wrote %d bytes of %d.\n" + , time_stamp(), num, msglen)); + errno = myerrno; + } + break; + } + + case SOCKET_WAIT_ACCEPT: + { + /* Default to accepting the socket. */ + erq_accept(mesg, msglen); + return; + } + + default: + { + char r_ticket[] = { ERQ_E_TICKET }; + reply1(get_handle(mesg), r_ticket, sizeof(r_ticket)); + return; + } + } /* switch(socket->type) */ + + /* Return the success of the action */ + + if (num == msglen) + { + char r_ok[] = { ERQ_OK, 0 }; + reply1(get_handle(mesg), r_ok, sizeof(r_ok)); + return; + } + else if (num >= 0) + { + XPRINTF((stderr, "%s Queue remaining data: %p:%d\n" + , time_stamp(), mesg+num, msglen-num)); + add_to_queue(&sp->queue, data+num, msglen-num, get_handle(mesg)); + num=htonl(num); + replyn(get_handle(mesg), 1, 2, + (char[]) { ERQ_E_INCOMPLETE }, 1, + (char *)&num, 4); + return; + } + + reply_errno(get_handle(mesg)); + if ( errno != EWOULDBLOCK +#if EWOULDBLOCK!=EAGAIN + && errno != EAGAIN +#endif + ) + { + XPRINTF((stderr, "%s Error %d when writing data.\n" + , time_stamp(), errno)); + close_socket(sp); + } +} /* erq_send() */ + +/*-------------------------------------------------------------------------*/ +void +erq_listen (char *mesg, int msglen) + +/* ERQ_LISTEN: Open a socket to listen for connections. + */ + +{ + struct sockaddr_in addr; + socket_t *sp; + int fd, tmp; + + /* Check if the message is ok */ + if (msglen != 11) + { + char r_arglen[] = { ERQ_E_ARGLENGTH, 0 }; + reply1(get_handle(mesg), r_arglen, sizeof(r_arglen)); + return; + } + + /* Get the port number */ + addr.sin_addr.s_addr=INADDR_ANY; + addr.sin_family=AF_INET; + memcpy(&addr.sin_port, mesg + 9, 2); + + /* Open and initialise the socket */ + tmp=((fd=socket(AF_INET, SOCK_STREAM, 0)) < 0); + tmp=tmp || (fcntl(fd, F_SETFD, 1) < 0); + tmp=tmp || (fcntl(fd, F_SETFL, O_NONBLOCK) < 0); + tmp=tmp || (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&msglen, + sizeof(msglen)) < 0); + tmp=tmp || (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0); + tmp=tmp || (listen(fd, 5) < 0); + if (tmp) + { + if (fd >= 0) + close(fd); + reply_errno(get_handle(mesg)); + return; + } + + /* Make the new socket structure */ + sp = new_socket(fd, SOCKET_LISTEN); + sp->handle = get_handle(mesg); + + { + char r_ok[] = { ERQ_OK }; + replyn(sp->handle, 1, 2, + r_ok, sizeof(r_ok), + (char *) &sp->ticket, TICKET_SIZE); + } +} /* erq_listen() */ + +/*-------------------------------------------------------------------------*/ +void +erq_open_udp (char *mesg, int msglen) + +/* ERQ_OPEN_UDP: Open an UDP socket. + */ + +{ + struct sockaddr_in addr; + socket_t *sp; + int fd, tmp; + + if (msglen != 11) + { + char r_arglen[] = { ERQ_E_ARGLENGTH, 0 }; + reply1(get_handle(mesg), r_arglen, sizeof(r_arglen)); + return; + } + + /* Get the port to use */ + addr.sin_addr.s_addr = INADDR_ANY; + addr.sin_family = AF_INET; + memcpy(&addr.sin_port, mesg + 9, 2); + + /* Open and initialise the socket */ + + if ((fd=socket(AF_INET, SOCK_DGRAM, 0)) < 0 + || fcntl(fd, F_SETFD, 1) < 0 + || fcntl(fd, F_SETFL, O_NONBLOCK) < 0 + || setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&tmp, + sizeof(tmp)) < 0 + || bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) + { + if (fd >= 0) + close(fd); + reply_errno(get_handle(mesg)); + return; + } + + /* Create the new socket structure */ + sp = new_socket(fd, SOCKET_UDP); + sp->handle = get_handle(mesg); + + { + char r_ok[] = { ERQ_OK }; + replyn(sp->handle, 1, 2, + r_ok, sizeof(r_ok), + (char *) &sp->ticket, TICKET_SIZE); + } + return; +} /* erq_open_udp() */ + +/*-------------------------------------------------------------------------*/ +void +erq_open_tcp (char *mesg, int msglen) + +/* ERQ_OPEN_TCP: Open a TCP socket and connect it to a given address. + * If the connection can't be completed immediately (EINPROGRESS), the + * socket is set to SOCKET_WAIT_CONNECT. + */ + +{ + struct sockaddr_in addr; + socket_t *sp; + int fd, tmp, status; + + if (msglen != 15) + { + char r_arglen[] = { ERQ_E_ARGLENGTH, 0 }; + reply1(get_handle(mesg), r_arglen, sizeof(r_arglen)); + return; + } + + /* Get the address */ + memcpy(&addr.sin_addr.s_addr, mesg + 9, 4); + addr.sin_family=AF_INET; + memcpy(&addr.sin_port, mesg + 13, 2); + status=SOCKET_CONNECTED; + + /* Initialize the socket */ + if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0 + || fcntl(fd, F_SETFD, 1) < 0 + || fcntl(fd, F_SETFL, O_NONBLOCK) < 0) + { + if (fd >= 0) + close(fd); + reply_errno(get_handle(mesg)); + return; + } + + /* Try to connect */ + do + tmp=connect(fd, (struct sockaddr *) &addr, sizeof(addr)); + while (tmp && errno==EINTR); + + if (!tmp) + status = SOCKET_CONNECTED; + else if (errno == EINPROGRESS) + { + status = SOCKET_WAIT_CONNECT; + tmp = 0; + } + else + { + if (fd >= 0) + close(fd); + reply_errno(get_handle(mesg)); + return; + } + + /* Create the new socket structure */ + sp = new_socket(fd, status); + sp->handle = get_handle(mesg); + if (status == SOCKET_WAIT_CONNECT) + return; + + { + char r_ok[] = { ERQ_OK }; + replyn(sp->handle, 1, 2, + r_ok, sizeof(r_ok), + (char *) &sp->ticket, TICKET_SIZE); + } + return; +} /* erq_open_tcp() */ + +/*-------------------------------------------------------------------------*/ +void +erq_accept (char *mesg, int msglen) + +/* ERQ_ACCEPT: Accept a new, pending connection. + */ + +{ + struct sockaddr_in addr; + socket_t *sp; + int fd; + length_t tmp; + + if (msglen != 9+TICKET_SIZE) + { + char r_arglen[] = { ERQ_E_ARGLENGTH, 0 }; + reply1(get_handle(mesg), r_arglen, sizeof(r_arglen)); + return; + } + + /* Find the socket we're accepting on */ + for (sp = sockets; sp; sp = sp->next) + if (!memcmp(mesg+9, &sp->ticket, TICKET_SIZE)) + break; + + /* Is there really something pending? */ + if (sp->type != SOCKET_WAIT_ACCEPT) + { + char r_ticket[] = { ERQ_E_TICKET }; + reply1(get_handle(mesg), r_ticket, sizeof(r_ticket)); + return; + } + + /* Yes, mark the socket as available again */ + sp->type = SOCKET_LISTEN; + + /* Accept and initialize the socket */ + tmp = sizeof(addr); + if ((fd=accept(sp->fd, (struct sockaddr *)&addr, &tmp)) < 0 + || fcntl(fd, F_SETFD, 1) < 0 + || fcntl(fd, F_SETFL, O_NONBLOCK) < 0) + { + if (fd >= 0) + close(fd); + reply_errno(get_handle(mesg)); + return; + } + + /* Create the socket */ + sp = new_socket(fd, SOCKET_CONNECTED); + sp->handle = get_handle(mesg); + + { + char r_ok[] = { ERQ_OK }; + replyn(sp->handle = get_handle(mesg), 1, 4, + r_ok, sizeof(r_ok), + (char *) &addr.sin_addr.s_addr, 4, + (char *) &addr.sin_port, 2, + (char *) &sp->ticket, TICKET_SIZE); + } +} /* erq_accept() */ + +/*-------------------------------------------------------------------------*/ +static int +send_auth (auth_t *ap) + +/* We got connection to the authd - send our request. + * Return 0 on success, 1 if an error occured and the socket has been closed. + */ + +{ + char req[100]; + int num; + + sprintf(req, "%ld,%ld\n", ap->remote_port, ap->local_port); + do + num = write(ap->s.fd, req, strlen(req)); + while(num == -1 && errno == EINTR); + if (num <= 0) + { + close_socket((socket_t *)ap); + return 1; + } + + return 0; +} /* send_auth() */ + +/*-------------------------------------------------------------------------*/ +void +erq_auth (char *mesg, int msglen) + +/* ERQ_AUTH: Connect to a remote authd and request authentification. + * If the connection can't be completed immediately (EINPROGRESS), the + * socket is set to SOCKET_WAIT_AUTH. + */ + +{ + struct sockaddr_in addr; + auth_t *ap; + int fd, tmp, status, local_port, remote_port; + + switch(msglen) { + case 17: + { + /* The xerq way */ + unsigned short sh; + + memcpy(&sh, mesg+13, sizeof(sh)); remote_port = ntohs(sh); + memcpy(&sh, mesg+15, sizeof(sh)); local_port = ntohs(sh); + + memcpy(&addr.sin_addr.s_addr, mesg+9, 4); + addr.sin_family = AF_INET; + addr.sin_port = htons(AUTH_PORT); + break; + } + + case 13+sizeof(addr): + { + /* The standard erq way */ + memcpy(&addr, mesg+9, sizeof(addr)); + remote_port = ntohs(addr.sin_port); + local_port = read_32(mesg+sizeof(addr)+9); + addr.sin_port = htons(AUTH_PORT); + break; + } + + default: + { + reply1(get_handle(mesg), "", 0); + return; + } + } + + /* Create and initialize the socket */ + if ((fd=socket(AF_INET, SOCK_STREAM, 0))<0 + || fcntl(fd, F_SETFD, 1)<0 + || fcntl(fd, F_SETFL, O_NONBLOCK)<0) + { + if (fd >= 0) + close(fd); + reply1(get_handle(mesg), "", 0); + return; + } + + /* Try to connect to the authd */ + do + tmp = connect(fd, (struct sockaddr *) &addr, sizeof(addr)); + while(tmp && errno==EINTR); + + if (!tmp) + status = SOCKET_AUTH; + else if (errno == EINPROGRESS) + status = SOCKET_WAIT_AUTH; + else + { + tmp = errno; + if (fd >= 0) + close(fd); + reply1(get_handle(mesg), "", 0); + return; + } + + /* Create the auth_t structure and put it into the list of sockets */ + ap = malloc(sizeof(struct auth_s)); + ap->s.next = sockets; + ap->s.fd = fd; + ap->s.type = status; + ap->s.ticket.seq = (seq_number+=seq_number); + ap->s.ticket.rnd = get_ticket(); + ap->s.handle = get_handle(mesg); + ap->s.queue = NULL; + ap->local_port = local_port; + ap->remote_port = remote_port; + ap->pos = 8; + sockets = (struct socket_s *)ap; + + /* If we already got connection, send our request */ + if (status == SOCKET_AUTH) + send_auth(ap); +} /* erq_auth() */ + +/***************************************************************************/ + diff --git a/src/version.sh b/src/version.sh index fd0674c..809eeba 100644 --- a/src/version.sh +++ b/src/version.sh @@ -1,29 +1,26 @@ # This file defines a number of shell variables to describe the projects # version. It is meant to be modified by the bumpversion script. -# -# Funny, we have to change the parsing for CVS versus SVN. -# Maybe we should start using SVN instead? Ye ye yeh # The checkin date -version_date=$(echo "\$Date: 2008/08/03 13:14:29 $$" | perl -pe 's%.*\b(\d+)/(\d+)/(\d+)\b.*%\1-\2-\3%') +version_date=$(echo "\$Date: 2009-01-12 21:08:20 -0700 (Mon, 12 Jan 2009) $" | sed -e 's/[$]Date: \([0-9]*-[0-9]*-[0-9]*\).*\$/\1/') # The checkin time -version_time=$(echo "\$Date: 2008/08/03 13:14:29 $$" | perl -pe 's%.*\b(\d+:\d+:\d+)\b.*%\1%') +version_time=$(echo "\$Date: 2009-01-12 21:08:20 -0700 (Mon, 12 Jan 2009) $" | sed -e 's/[$]Date: \([0-9]*-[0-9]*-[0-9]*\) \([0-9]*:[0-9]*:[0-9]*\).*\$/\2/') # The checkin revision -version_revision=$(echo "\$Revision: 1.58 $" | sed -e 's/[$]Revision: \([0-9]*\.[0-9]*\) *\$/\1/') +version_revision=$(echo "\$Revision: 2483 $" | sed -e 's/[$]Revision: \([0-9][0-9]*\) *\$/\1/') # The version type: dev, stable, maintenance, release version_type="stable" -version_longtype="binarius" +version_longtype="stable" # A timestamp, to be used by bumpversion and other scripts. # It can be used, for example, to 'touch' this file on every build, thus # forcing revision control systems to add it on every checkin automatically. -version_stamp="Tue Feb 24 14:02:45 CET 2009" +version_stamp="Thu May 21 23:49:43 CEST 2009" -# The version number information # Okay, LDMUD is using 3.x.x so to avoid conflicts let's just use 4.x.x version_major=4 version_minor=0 -version_micro=11 +version_micro=12 + diff --git a/src/xalloc.c b/src/xalloc.c index 9518f43..686aa9d 100644 --- a/src/xalloc.c +++ b/src/xalloc.c @@ -44,12 +44,37 @@ typedef struct { unsigned long counter, size; } t_stat; /* A counter type for statistics and its functions: */ -#define count(a,b) { a.size+=(b); if ((b)<0) --a.counter; else ++a.counter; } -#define count_up(a,b) { a.size+=(b); ++a.counter; } -#define count_up_n(a,b,c) { a.size+=(b)*(c); a.counter+=(b); } -#define count_add(a,b) { a.size+=(b); } -#define count_back(a,b) { a.size-=(b); --a.counter; } -#define count_back_n(a,b,c) { a.size-=(b)*(c); a.counter-=(b); } +static inline void count_add(t_stat *a, unsigned long b) { + a->size += b; +} + +static inline void count(t_stat *a, unsigned long b) { + count_add(a, b); + if (b < 0) + --a->counter; + else + ++a->counter; +} + +static inline void count_up(t_stat *a, unsigned long b) { + count_add(a, b); + ++a->counter; +} + +static inline void count_up_n(t_stat *a, unsigned long b, unsigned long c) { + count_add(a, b * c); + a->counter += b; +} + +static inline void count_back(t_stat *a, unsigned long b) { + count_add(a, -b); + --a->counter; +} + +static inline void count_back_n(t_stat *a, unsigned long b, unsigned long c) { + count_add(a, -(b * c)); + a->counter -= b; +} typedef p_uint word_t; /* Our 'word' type. @@ -557,9 +582,9 @@ xalloc_traced (size_t size MTRACE_DECL) p[XM_PC] = (word_t)inter_pc; #endif #ifdef NO_MEM_BLOCK_SIZE - count_up(xalloc_stat, XM_OVERHEAD_SIZE); + count_up(&xalloc_stat, XM_OVERHEAD_SIZE); #else - count_up(xalloc_stat, mem_block_size(p)); + count_up(&xalloc_stat, mem_block_size(p)); if (check_max_malloced()) return NULL; #endif @@ -578,9 +603,9 @@ xfree (POINTER p) { word_t *q = (word_t*)p - XM_OVERHEAD; #ifdef NO_MEM_BLOCK_SIZE - count_back(xalloc_stat, XM_OVERHEAD_SIZE); + count_back(&xalloc_stat, XM_OVERHEAD_SIZE); #else - count_back(xalloc_stat, mem_block_size(q)); + count_back(&xalloc_stat, mem_block_size(q)); #endif mem_free(q); } @@ -675,8 +700,8 @@ malloc_increment_size (void *vp, size_t size) #ifndef NO_MEM_BLOCK_SIZE if (rc != NULL) { - count_back(xalloc_stat, old_size); - count_up(xalloc_stat, mem_block_size(block)); + count_back(&xalloc_stat, old_size); + count_up(&xalloc_stat, mem_block_size(block)); if (check_max_malloced()) return NULL; } @@ -751,8 +776,8 @@ rexalloc_traced (POINTER p, size_t size MTRACE_DECL if (t) { #ifndef NO_MEM_BLOCK_SIZE - count_back(xalloc_stat, old_size); - count_up(xalloc_stat, mem_block_size(t)); + count_back(&xalloc_stat, old_size); + count_up(&xalloc_stat, mem_block_size(t)); if (check_max_malloced()) return NULL; #endif @@ -1264,7 +1289,7 @@ malloc (size_t size) result = amalloc(size); if (result) { - count_up(clib_alloc_stat, get_block_size(result)); + count_up(&clib_alloc_stat, get_block_size(result)); } return result; @@ -1280,7 +1305,7 @@ free (POINTER ptr) { if (ptr) { - count_back(clib_alloc_stat, get_block_size(ptr)); + count_back(&clib_alloc_stat, get_block_size(ptr)); } afree(ptr); diff --git a/src/xalloc.h b/src/xalloc.h index 16e23de..5bf1ff3 100644 --- a/src/xalloc.h +++ b/src/xalloc.h @@ -16,8 +16,8 @@ #define xallocate(dest,size,txt) \ if (NULL == ((dest) = xalloc(size))) {\ - errorf("(%s:%d) Out of memory (%lu bytes) for %s\n"\ - , __FILE__, __LINE__, (unsigned long)(size), txt); \ + errorf("(%s:%d) Out of memory (%zu bytes) for %s\n"\ + , __FILE__, __LINE__, (size_t)(size), txt); \ } else {} @@ -41,12 +41,12 @@ errorf("(%s:%d) Out of memory for %s\n", __FILE__, __LINE__, txt) #define outofmem(size,txt) \ - errorf("(%s:%d) Out of memory (%lu bytes) for %s\n"\ - , __FILE__, __LINE__, (unsigned long)(size), txt) + errorf("(%s:%d) Out of memory (%zu bytes) for %s\n"\ + , __FILE__, __LINE__, (size_t)(size), txt) #define outofmem1(size,txt,arg1) \ - errorf("(%s:%d) Out of memory (%lu bytes) for " txt "\n"\ - , __FILE__, __LINE__, (unsigned long)(size), arg1) + errorf("(%s:%d) Out of memory (%zu bytes) for " txt "\n"\ + , __FILE__, __LINE__, (size_t)(size), arg1) /* void memsafe(void * expr, size_t size, const char * txt) @@ -59,8 +59,8 @@ do { \ size_t memsafe_size = size; \ if (NULL == (expr)) {\ - errorf("(%s:%d) Out of memory (%lu bytes) for %s\n"\ - , __FILE__, __LINE__, (unsigned long)(memsafe_size), txt); \ + errorf("(%s:%d) Out of memory (%zu bytes) for %s\n"\ + , __FILE__, __LINE__, (size_t)(memsafe_size), txt); \ } else {} \ } while(0) @@ -124,11 +124,15 @@ extern int stack_direction; extern size_t xalloced_size (POINTER p); extern size_t xalloc_overhead (void); -extern POINTER xalloc_traced(size_t size MTRACE_DECL) MALLOC; +extern POINTER xalloc_traced(size_t size MTRACE_DECL) + MALLOC __attribute__ ((warn_unused_result)); extern void xfree(POINTER); -extern POINTER rexalloc_traced(POINTER, size_t MTRACE_DECL) MALLOC; -extern POINTER pxalloc_traced(size_t MTRACE_DECL) MALLOC; -extern POINTER prexalloc_traced(POINTER, size_t MTRACE_DECL) MALLOC; +extern POINTER rexalloc_traced(POINTER, size_t MTRACE_DECL) + MALLOC __attribute__ ((warn_unused_result)); +extern POINTER pxalloc_traced(size_t MTRACE_DECL) + MALLOC __attribute__ ((warn_unused_result)); +extern POINTER prexalloc_traced(POINTER, size_t MTRACE_DECL) + MALLOC __attribute__ ((warn_unused_result)); extern void pfree(POINTER); extern void * malloc_increment_size (void *vp, size_t size); @@ -140,7 +144,7 @@ extern Bool x_test_ref (POINTER p); #ifdef MALLOC_TRACE extern void store_print_block_dispatch_info(void *block, void (*func)(int, void *, int) ); -extern int is_freed(void *p, p_uint minsize); +extern Bool is_freed(void *p, p_uint minsize); #endif /* MALLOC_TRACE */ #ifdef CHECK_OBJECT_GC_REF diff --git a/src/xptmalloc.c b/src/xptmalloc.c index 2fe93c3..fe73847 100644 --- a/src/xptmalloc.c +++ b/src/xptmalloc.c @@ -235,7 +235,8 @@ static Bool mem_is_freed (POINTER p, size_t minsize) { * See above for the *BSD situation. */ -#if !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__OpenBSD__) +#if defined(SBRK_OK) && \ + !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__OpenBSD__) #define REPLACE_MALLOC #endif @@ -249,7 +250,9 @@ void ptmalloc_ref_unused(void) { in_malloc = 0; print_block(0, 0); - count_up(clib_alloc_stat, 0); +#ifdef REPLACE_MALLOC + count_up(&clib_alloc_stat, 0); +#endif } /***************************************************************************/